2009-07-07 20 views
5

tengo un problema con la consulta a continuación en postgresSUBSTR no trabajar con el tipo de datos "marca de tiempo" en Postgres 8.3

SELECT u.username,l.description,l.ip,SUBSTRING(l.createdate,0,11) as createdate,l.action 
FROM n_logs AS l LEFT JOIN n_users AS u ON u.id = l.userid 
WHERE SUBSTRING(l.createdate,0,11) >= '2009-06-07' 
    AND SUBSTRING(l.createdate,0,11) <= '2009-07-07'; 

Siempre he utilizado la consulta anterior en una versión anterior de Postgres y funcionó al 100%. Ahora, con la nueva versión de posgres me da errores como continuación

**ERROR: function pg_catalog.substring(timestamp without time zone, integer, integer) does not exist 
LINE 1: SELECT u.username,l.description,l.ip,SUBSTRING(l.createdate,... 
              ^
HINT: No function matches the given name and argument types. You might need to add explicit type casts.** 

supongo que tiene algo que ver con los tipos de datos, que los datos es una zona horaria y que subcadena sólo son compatibles con los tipos de datos de cadena, ahora mi pregunta es ¿qué ¿Puedo hacer mi consulta para que aparezcan mis resultados?

Respuesta

6

La solución explícita a su problema es convertir la fecha y hora a la cadena.

..., SUBSECUENCIA (l.createdate :: varchar, ...

Ahora, esto no es en absoluto una buena práctica utilizar el resultado de comparar fechas.

Por lo tanto, la buena solución a su necesidad es para cambiar la consulta utilizando las explícitas datetime manipulation, comparison y formatting funciones, como el extracto() y to_char()

Habría que cambiar la consulta de tener una cláusula como

l.createdate::DATE >= '2009-06-07'::DATE 
AND l.createdate::DATE < '2009-07-08'::DATE; 

o una de las siguientes alternativas

+0

no sabía nada de esto, pero esto solucionó mi problema – Roland

5
SELECT u.username, l.description, l.ip, 
     CAST(l.createdate AS DATE) as createdate, 
     l.action 
FROM n_logs AS l 
LEFT JOIN 
     n_users AS u 
ON  u.id = l.userid 
WHERE l.createdate >= '2009-06-07'::TIMESTAMP 
     AND l.createdate < '2009-07-07'::TIMESTAMP + '1 DAY'::INTERVAL 
+0

Je, 1 esto tiene más sentido, no he leído la consulta ¡hasta el final! (/ yo castigo a uno mismo). –

1

Una variación en la respuesta de la Quassnoi (que realmente debería aceptar en lugar de esto.):

SELECT 
    u.username, 
    l.description, 
    l.ip, 
    CAST(l.createdate AS DATE) as createdate, 
    l.action 
FROM 
    n_logs AS l 
LEFT JOIN 
    n_users AS u 
ON 
    (u.id = l.userid) 
WHERE 
    l.createdate::DATE BETWEEN '2009-06-07'::DATE AND '2009-07-07'::DATE 
+0

@Milen: no es sargable – Quassnoi

+0

Pero es correcto y legible. –

1

no estoy seguro de lo que quiere para lograr, pero básicamente "subserie" en los tipos de datos de fecha no está realmente bien definido, ya que depende del formato externo de dichos datos.

En la mayoría de los casos debe utilizar las funciones extract() o to_char().

En general, para devolver datos, usted quiere to_char(), y para operaciones en él (incluida la comparación) - extract(). Hay algunos casos donde esta regla general no se aplica, pero estos son generalmente signos de una estructura de datos que no está realmente bien pensada.

Ejemplo:

# select to_char(now(), 'YYYY-MM-DD'); 
    to_char 
------------ 
2009-07-07 
(1 row) 

Para extracto vamos a escribir una consulta simple que mostrará una lista de todos los objetos creados después de las 8:

select * from objects where extract(hour from created) >= 20; 
+0

Buen punto acerca de la indefinición de subcadenas en los tipos de fecha –

0

Si utiliza PostgreSQL, recibirá:

select('SUBSTRING(offer.date_closed, 0, 11)') 

función substr (indicación de fecha y hora sin zona horaria integ er número entero) no lo hace existen

Uso:

select('SUBSTRING(CONCAT(offer.date_closed, \'\'), 0, 11)') 
Cuestiones relacionadas