2009-07-07 6 views
5

J'ai un problème avec la requête ci-dessous dans PostgresSUBSTR ne fonctionne pas avec le type de données « horodatage » dans 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'; 

J'ai toujours utilisé la requête ci-dessus dans une version antérieure de Postgres et cela a fonctionné à 100%. Maintenant, avec la nouvelle version de posgres il me donne des erreurs comme ci-dessous

**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.** 

Je suppose qu'il a quelque chose à voir avec les types de données, que les données sont un fuseau horaire et que substring ne supporte que des données de type chaîne, maintenant ma question est ce que puis-je faire à propos de ma requête pour que mes résultats arrivent?

Répondre

6

La solution explicite à votre problème consiste à convertir le datetime en chaîne.

..., SUBSTRING (l.createdate :: varchar, ...

Maintenant, ce n'est pas du tout une bonne pratique d'utiliser le résultat de comparer les dates.

Ainsi, le bonne solution pour votre besoin est de changer votre requête en utilisant les datetime manipulation, comparison et formatting explicites fonctions, comme l'extrait() et to_char()

Vous devriez changer votre requête d'avoir une clause comme

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

ou l'une des alternatives ci-dessous

+0

Je ne savais pas, mais ce problème a résolu mon – 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

Heh, +1 cela fait plus de sens, je ne l'ai pas lu la requête jusqu'à la fin! (/ moi punit soi-même). –

1

Une variante de la réponse de Quassnoi (que vous devriez vraiment accepter au lieu de cela.):

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: ce n'est pas sargable – Quassnoi

+0

Mais c'est correct et lisible. –

1

Je ne suis pas sûr de ce que vous voulez pour atteindre, mais fondamentalement "sous-chaîne" sur les types de données de date n'est pas vraiment bien défini, car il dépend du format externe de ces données. Dans la plupart des cas, utilisez les fonctions extract() ou to_char().

Généralement - pour retourner les données que vous voulez to_char(), et pour les opérations sur celui-ci (y compris la comparaison) - extract(). Il y a des cas où cette règle générale ne s'applique pas, mais ce sont généralement des signes d'une structure de données pas vraiment bien pensée.

Exemple:

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

Pour extrait Écrivons une simple requête qui liste tous les objets créés après 20 heures:

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

Bon point sur l'indéfini de la sous-chaîne sur les types de date –

0

Si vous utilisez Postgresql, vous recevrez:

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

function substr (horodatage sans fuseau horaire integ entier er) ne existe

Utilisation:

select('SUBSTRING(CONCAT(offer.date_closed, \'\'), 0, 11)') 
Questions connexes