make_date e make_time montam um valor a partir de numeros ja prontos: voce passa o ano, o mes e o dia (ou a hora, o minuto e o segundo) como inteiros separados, sem analisar uma string. Sao a ferramenta ideal quando as partes de uma data ja estao em colunas diferentes de um relatorio.
Sintaxe basica
make_date(year, month, day) retorna um date, e make_time(hour, min, sec) retorna um time. Os argumentos sao inteiros (os segundos sao double precision para guardar uma fracao). Nao ha strings de formato como 'YYYY-MM-DD' nem as surpresas de localidade que vem com elas.
SELECT
make_date(2024, 3, 15) AS d,
make_time(14, 30, 0) AS t;
Os segundos aceitam uma fracao, entao um momento com precisao de milissegundos e montado sem converter strings:
SELECT make_time(9, 5, 30.5) AS t;
Um timestamp completo vem de make_timestamp(year, month, day, hour, min, sec), e a versao com fuso e make_timestamptz(...).
Montar uma data a partir de colunas separadas
O cenario principal e uma tabela onde o ano, o mes e o dia sao guardados como numeros em campos distintos. Suponha que uma carga de uma origem legada deixou as partes da data separadas:
SELECT
order_id,
make_date(y, m, d) AS order_date
FROM order_parts;
make_date elimina a dor da concatenacao e do CAST: voce nao precisa montar a string y || '-' || m || '-' || d e torcer para que um mes de um digito nao quebre o formato. Os numeros entram na funcao como estao.
O mesmo truque e util para filtrar por uma data montada a partir de parametros. Todos os pedidos de um dia especifico, montados a partir de tres numeros:
SELECT id, user_id, amount
FROM orders
WHERE created_at::date = make_date(2024, 3, 15)
AND status = 'paid';
Validacao de partes fora do intervalo
make_date nao fica calado diante de um absurdo: um valor fora do intervalo valido gera um erro em vez de avancar para o mes seguinte como faz a aritmetica de intervalos.
SELECT make_date(2024, 13, 1);
SELECT make_date(2024, 2, 30);
Isso e ao mesmo tempo uma vantagem e uma armadilha:
- Vantagem: dados sujos (mes
13, dia 0) sao detectados na hora em vez de virarem em silencio uma data errada.
- Pegadinha: uma unica linha quebrada em uma varredura grande derruba a consulta inteira. Se os dados nao estao limpos, valide as partes antes.
Proteja-se contra linhas ruins com um filtro previo:
SELECT order_id, make_date(y, m, d) AS order_date
FROM order_parts
WHERE m BETWEEN 1 AND 12
AND d BETWEEN 1 AND 31;
Um ano negativo e lido como antes de Cristo, entao make_date(-1, 1, 1) nao e um erro, mas 0001-01-01 BC. O ano zero e rejeitado.
Quando make_time compensa
make_time brilha quando a hora e o minuto vem de uma configuracao ou de um join. Por exemplo, normalizar a "janela de trabalho" de um departamento para um unico horario de inicio:
SELECT
e.dept,
COUNT(*) AS people,
make_time(9, 0, 0) AS shift_start
FROM employees e
GROUP BY e.dept;
O time ja montado pode ser somado a uma data para obter um momento completo sem analisar strings:
SELECT
u.id,
make_date(2024, 3, 15) + make_time(18, 0, 0) AS reminder_at
FROM users u
WHERE u.country = 'DE';
Diferencas no MySQL e ClickHouse
Os nomes e o comportamento diferem do PostgreSQL.
- MySQL nao tem
make_date no sentido habitual. Tem MAKEDATE(year, dayofyear), que espera um ano e um dia do ano, nao um mes e um dia. Para montar a partir de mes e dia usa-se STR_TO_DATE, e para a hora usa-se MAKETIME(hour, minute, second).
SELECT
STR_TO_DATE('2024-3-15', '%Y-%c-%e') AS d,
MAKETIME(14, 30, 0) AS t;
- ClickHouse oferece
makeDate(year, month, day) e makeDateTime(year, month, day, hour, minute, second), cujos nomes coincidem em sentido com o PostgreSQL.
SELECT
makeDate(2024, 3, 15) AS d,
makeDateTime(2024, 3, 15, 14, 30, 0) AS t;
A diferenca chave ao portar: o MySQL MAKEDATE recebe um dia do ano, nao um mes e um dia, e engole sem reclamar uma entrada que o PostgreSQL rejeitaria. Sempre confira a assinatura antes de mover uma consulta entre bancos.
make_dateemake_timemontam um valor a partir de numeros ja prontos: voce passa o ano, o mes e o dia (ou a hora, o minuto e o segundo) como inteiros separados, sem analisar uma string. Sao a ferramenta ideal quando as partes de uma data ja estao em colunas diferentes de um relatorio.Sintaxe basica
make_date(year, month, day)retorna umdate, emake_time(hour, min, sec)retorna umtime. Os argumentos sao inteiros (os segundos saodouble precisionpara guardar uma fracao). Nao ha strings de formato como'YYYY-MM-DD'nem as surpresas de localidade que vem com elas.SELECT make_date(2024, 3, 15) AS d, -- 2024-03-15 make_time(14, 30, 0) AS t; -- 14:30:00Os segundos aceitam uma fracao, entao um momento com precisao de milissegundos e montado sem converter strings:
SELECT make_time(9, 5, 30.5) AS t; -- 09:05:30.5Um timestamp completo vem de
make_timestamp(year, month, day, hour, min, sec), e a versao com fuso emake_timestamptz(...).Montar uma data a partir de colunas separadas
O cenario principal e uma tabela onde o ano, o mes e o dia sao guardados como numeros em campos distintos. Suponha que uma carga de uma origem legada deixou as partes da data separadas:
-- order_parts(order_id, y, m, d) SELECT order_id, make_date(y, m, d) AS order_date FROM order_parts;make_dateelimina a dor da concatenacao e doCAST: voce nao precisa montar a stringy || '-' || m || '-' || de torcer para que um mes de um digito nao quebre o formato. Os numeros entram na funcao como estao.O mesmo truque e util para filtrar por uma data montada a partir de parametros. Todos os pedidos de um dia especifico, montados a partir de tres numeros:
SELECT id, user_id, amount FROM orders WHERE created_at::date = make_date(2024, 3, 15) AND status = 'paid';Validacao de partes fora do intervalo
make_datenao fica calado diante de um absurdo: um valor fora do intervalo valido gera um erro em vez de avancar para o mes seguinte como faz a aritmetica de intervalos.SELECT make_date(2024, 13, 1); -- ERROR: date field value out of range SELECT make_date(2024, 2, 30); -- ERROR: date field value out of rangeIsso e ao mesmo tempo uma vantagem e uma armadilha:
13, dia0) sao detectados na hora em vez de virarem em silencio uma data errada.Proteja-se contra linhas ruins com um filtro previo:
SELECT order_id, make_date(y, m, d) AS order_date FROM order_parts WHERE m BETWEEN 1 AND 12 AND d BETWEEN 1 AND 31;Um ano negativo e lido como antes de Cristo, entao
make_date(-1, 1, 1)nao e um erro, mas0001-01-01 BC. O ano zero e rejeitado.Quando make_time compensa
make_timebrilha quando a hora e o minuto vem de uma configuracao ou de um join. Por exemplo, normalizar a "janela de trabalho" de um departamento para um unico horario de inicio:SELECT e.dept, COUNT(*) AS people, make_time(9, 0, 0) AS shift_start FROM employees e GROUP BY e.dept;O
timeja montado pode ser somado a uma data para obter um momento completo sem analisar strings:SELECT u.id, make_date(2024, 3, 15) + make_time(18, 0, 0) AS reminder_at FROM users u WHERE u.country = 'DE';Diferencas no MySQL e ClickHouse
Os nomes e o comportamento diferem do PostgreSQL.
make_dateno sentido habitual. TemMAKEDATE(year, dayofyear), que espera um ano e um dia do ano, nao um mes e um dia. Para montar a partir de mes e dia usa-seSTR_TO_DATE, e para a hora usa-seMAKETIME(hour, minute, second).SELECT STR_TO_DATE('2024-3-15', '%Y-%c-%e') AS d, -- 2024-03-15 MAKETIME(14, 30, 0) AS t; -- 14:30:00makeDate(year, month, day)emakeDateTime(year, month, day, hour, minute, second), cujos nomes coincidem em sentido com o PostgreSQL.SELECT makeDate(2024, 3, 15) AS d, makeDateTime(2024, 3, 15, 14, 30, 0) AS t;A diferenca chave ao portar: o MySQL
MAKEDATErecebe um dia do ano, nao um mes e um dia, e engole sem reclamar uma entrada que o PostgreSQL rejeitaria. Sempre confira a assinatura antes de mover uma consulta entre bancos.