2011-04-04 16 views
11

Recientemente, me he estado familiarizando con PostgreSQL (usando 8.2) y encontré la función date_trunc extremadamente útil para comparar fácilmente las marcas de tiempo entre ciertos días/meses/etc. La verdadera utilidad de la función, creo, proviene del hecho de que mantiene la salida en el formato de una marca de tiempo.Date_trunc de PostgreSQL en mySQL

He tenido que cambiar a mySQL (5.0) y encontrar algunas de las funciones de fecha bastante deficientes en comparación. La función extraer parece útil y la función de fecha que he encontrado resuelve algunos de mis problemas, pero ¿hay alguna forma de replicar el date_trunc de PostgreSQL?

A continuación se presenta un ejemplo de cómo solía utilizar date_trunc para que coincida con las marcas de tiempo consultados a sólo los últimos 4 meses, incluido el mes en curso, pero sólo si ha pasado una semana en lo que va del mes:

WHERE date_trunc('month', QUERY_DATE) BETWEEN 
    date_trunc('month', now()) - INTERVAL '4 MONTH' AND 
    date_trunc('month', now() - INTERVAL '1 WEEK') 

I no tengo idea de cómo recrear esa estipulación en mySQL. Entonces, mi pregunta al final del día es si este tipo de consulta se puede lograr en mySQL al intentar replicar date_trunc (y cómo) o si necesito comenzar a buscar estos tipos de consultas de una manera diferente para que funcionen. en mySQL (y sugerencias sobre cómo hacer eso)?

Respuesta

21

La función de extracción parece útil y la función de la fecha he encontrado resuelve algunos de mis problemas, pero ¿hay alguna manera de replicar date_trunc de PostgreSQL?

De hecho, EXTRACT parece que va a ser la coincidencia más cercana para este caso específico.

Su código original en PG:

WHERE date_trunc('month', QUERY_DATE) BETWEEN 
    date_trunc('month', now()) - INTERVAL '4 MONTH' AND 
    date_trunc('month', now() - INTERVAL '1 WEEK') 

usando EXTRACT:

WHERE EXTRACT(YEAR_MONTH FROM QUERY_DATE) 
     BETWEEN 
      EXTRACT(YEAR_MONTH FROM NOW() - INTERVAL 4 MONTH) 
     AND 
      EXTRACT(YEAR_MONTH FROM NOW() - INTERVAL 1 WEEK) 

Si bien debe ser funcionalmente idénticos, esto es en realidad la mutilación de las fechas en una cadena AAAAMM antes de hacer la comparación.

Otra opción sería utilizar DATE_FORMAT para reconstruir la cadena de fecha y obligarlo a comienzos del mes:

WHERE DATE_FORMAT(QUERY_DATE, '%Y-%m-01') 
     BETWEEN 
      DATE_FORMAT(NOW() - INTERVAL 4 MONTH, '%Y-%m-01') 
     AND 
      DATE_FORMAT(NOW() - INTERVAL 1 WEEK, '%Y-%m-01') 

Además, tenga en cuenta que MySQL es muy pobre en tratar con intervalos de tiempo, incluso cuando el el campo está indexado. Probablemente termines con una exploración de tabla completa si no tienes cuidado.

3

tarde a la fiesta, pero ...

hay una manera de conseguir la fecha truncada da conoce el intervalo. Por ejemplo, si el intervalo es MONTH, se podía obtener la fecha de hoy (now()) trunca al mes utilizando la siguiente:

select date_add('1900-01-01', interval TIMESTAMPDIFF(MONTH, '1900-01-01', now()) MONTH); 

Dado lo anterior, se podría crear una función de cuidar de los otros intervalos, así :

DELIMITER // 
create function date_trunc(vInterval varchar(7), vDate timestamp) 
returns timestamp 
begin 
    declare toReturn timestamp; 

    if vInterval = 'year' then set toReturn = date_add('1900-01-01', interval TIMESTAMPDIFF(YEAR, '1900-01-01', vDate) YEAR); 
    elseif vInterval = 'quarter' then set toReturn = date_add('1900-01-01', interval TIMESTAMPDIFF(QUARTER, '1900-01-01', vDate) QUARTER); 
    elseif vInterval = 'month' then set toReturn = date_add('1900-01-01', interval TIMESTAMPDIFF(MONTH, '1900-01-01', vDate) MONTH); 
    elseif vInterval = 'week' then set toReturn = date_add('1900-01-01', interval TIMESTAMPDIFF(WEEK, '1900-01-01', vDate) WEEK); 
    elseif vInterval = 'day' then set toReturn = date_add('1900-01-01', interval TIMESTAMPDIFF(DAY, '1900-01-01', vDate) DAY); 
    elseif vInterval = 'hour' then set toReturn = date_add('1900-01-01', interval TIMESTAMPDIFF(HOUR, '1900-01-01', vDate) HOUR); 
    elseif vInterval = 'minute' then set toReturn = date_add('1900-01-01', interval TIMESTAMPDIFF(MINUTE, '1900-01-01', vDate) MINUTE); 
    END IF; 

    return toReturn; 
end// 
DELIMITER ; 

se usa así:

select date_trunc('quarter', now()) 
Cuestiones relacionadas