2010-06-18 8 views
2

Une question SQL difficile (j'utilise postgres d'ailleurs).SQL - Première ligne insérée tous les jours pendant les X derniers jours

J'ai besoin de la première ligne insérée tous les jours pour les X derniers jours. une de mes colonnes est un horodatage, dont je tiens l'heure insérée, et une autre colonne est l'identifiant de ligne.

S'il n'est pas possible d'insérer la première rangée tous les jours, j'en ai au moins besoin d'une unique; une seule rangée pour chaque jour pendant les x derniers jours.

Des suggestions?

Merci

okie

Répondre

4

Vous voudrez peut-être essayer quelque chose comme ce qui suit (testé dans MySQL, mais je suppose que ce devrait être facile au port à Postgres):

SELECT  l.id, l.timestamp, l.value 
FROM  log l 
INNER JOIN (
      SELECT MIN(timestamp) first_timestamp 
      FROM  log 
      GROUP BY DATE(timestamp) 
      ) sub_l ON (sub_l.first_timestamp = l.timestamp) 
WHERE  l.timestamp > DATE_ADD(NOW(), INTERVAL -30 DAY); 

Notez que Cela suppose que vos horodatages sont uniques.

Test Case (MySQL):

CREATE TABLE log (id int, timestamp datetime, value int); 

INSERT INTO log VALUES (1, '2010-06-01 02:00:00', 100); 
INSERT INTO log VALUES (2, '2010-06-01 03:00:00', 200); 
INSERT INTO log VALUES (3, '2010-06-01 04:00:00', 300); 
INSERT INTO log VALUES (4, '2010-06-02 02:00:00', 400); 
INSERT INTO log VALUES (5, '2010-06-02 03:00:00', 500); 
INSERT INTO log VALUES (6, '2010-06-03 02:00:00', 600); 
INSERT INTO log VALUES (7, '2010-06-04 02:00:00', 700); 
INSERT INTO log VALUES (8, '2010-06-04 03:00:00', 800); 
INSERT INTO log VALUES (9, '2010-06-05 05:00:00', 900); 
INSERT INTO log VALUES (10, '2010-06-05 03:00:00', 1000); 

Résultat:

+------+---------------------+-------+ 
| id | timestamp   | value | 
+------+---------------------+-------+ 
| 1 | 2010-06-01 02:00:00 | 100 | 
| 4 | 2010-06-02 02:00:00 | 400 | 
| 6 | 2010-06-03 02:00:00 | 600 | 
| 7 | 2010-06-04 02:00:00 | 700 | 
| 10 | 2010-06-05 03:00:00 | 1000 | 
+------+---------------------+-------+ 
5 rows in set (0.00 sec) 
+0

si vous avez ajouté un min (ID) à la table dérivée et une clause ID à la condition de jointure, vous pouvez contourner le "suppose que vos horodatages sont uniques" aussi. – potatopeelings

+0

@potatopeelings: Je ne pense pas que ce soit si facile. 'SELECT MIN (horodatage), MIN (id) FROM journal GROUP BY DATE (horodatage)' sur le cas de test ci-dessus retournera la dernière ligne comme '2010-06-05 03:00:00 | 9'. Si je devais ajouter une clause ID à la condition JOIN, elle ne correspondrait pas, car il n'y a pas de ligne dans la table avec timestamp = '' 2010-06-05 03:00:00 'AND id =' 9''. .. (Ceci est au moins en MySQL). –

+0

oh oui, vous avez raison. Ma faute. Il faudrait une sous-requête ou une jointure supplémentaire pour obtenir la ligne avec l'identifiant le plus bas parmi ceux qui ont le plus faible horodatage par jour. Comme vous l'avez souligné - pas aussi facile que le MIN, MIN. Pardon! – potatopeelings

3

M. Vassallo, vous êtes une rock star.

cela a bien fonctionné. voici la version postgres de votre SQL:

SELECT l.id, l.timestamp, l.value 
FROM log l 
INNER JOIN (
      SELECT MIN(timestamp) AS first_timestamp 
      FROM  log 
      GROUP BY DATE(timestamp) 
) sub_l ON (sub_l.first_timestamp = l.timestamp) 
WHERE  l.timestamp > NOW() - INTERVAL '30 DAY' ORDER BY l.timestamp; 

il n'y a pas besoin d'obtenir l'ID minimum parce que je ne peux pas garantir que les inserts seront dans l'ordre chronologique directe (l'horodatage n'est pas vraiment le temps inséré, mais un horodatage résidant dans les données, et les paquets de données peuvent tomber en panne).

J'apprécie vraiment l'aide. merci d'avoir regardé ça.

+0

désolé, cela devrait dire 'SELECT MIN (timestamp) AS first_timestamp' –

+0

Je suis content que cela a aidé. Et merci de poster la version de Postgres :) J'ai édité votre réponse pour corriger la partie 'MIN (horodatage) AS ...' comme vous l'avez suggéré. –

Questions connexes