2010-07-27 8 views
2

J'ai du code SQL qui insère des valeurs d'un autre système (non basé sur sql). l'une des valeurs que je reçois est un horodatage.SQL: besoin d'une seule ligne par horodatage particulier

Je peux obtenir plusieurs insertions qui ont le même horodatage (bien que différentes valeurs pour d'autres champs).

mon problème est que je suis en train d'obtenir le premier insert qui se passe tous les jours (en fonction de l'horodatage) depuis un jour donné (c.-à me donner la première insertion de chaque jour depuis le 28 Janvier 2007 ...)

mon code pour obtenir le premier horodatage de tous les jours est la suivante:

SELECT MIN(my_timestamp) AS first_timestamp 
FROM my_schema.my_table 
WHERE my_col1 = 'WHATEVER' 
AND my_timestamp > timestamp '2010-Jul-27 07:45:24' - INTERVAL '365 DAY' 
GROUP BY DATE (my_timestamp); 

Cela me fournit la liste des temps disponibles. Mais quand je me joins à ces temps, je peux obtenir plusieurs rangées, car il y a beaucoup de rangées qui me manquent. Donc pendant 365 jours, je pourrais avoir 5 000 lignes (je pourrais insérer 100 lignes à 00:00:00 tous les jours).

En supposant, dans l'exemple ci-dessus, my_table a les colonnes my_col1 et my_col2, comment puis-je obtenir exactement 365 lignes contenant my_col1 & my_col2? peu importe quelle ligne je reviens s'il y a plusieurs rangées pour une date; n'importe quelle rangée suffira.

c'est une question étrange. le problème global est: donné un horodatage, comment peut-on obtenir une ligne par timestamp même s'il y a plusieurs lignes qui ont cet horodatage (en supposant qu'il n'y ait pas d'autre priorité)?

merci pour l'aide à l'avance. Par exemple, disons que cette table a les colonnes suivantes: my_col1, my_col2 et my_timestamp.
Voici des exemples de valeurs (par ordre de my_col1 - my_col2 - my_timestamp):

  • 'my_val1' - 10 - '2010-07-01 01:01:01'
  • 'my_val2' - 11 - '2010-07-01 01:01:01'
  • 'mon_val3' - 12 - '2010-07-01 01:01:01'
  • 'mon_val4' - 13 - '2010-07-01 01: 1h02'
  • 'my_val5' - 14 - '02.07.2010 01:01:01'
  • 'my_val6' - 15 - '02.07.2010 01:01:01'
  • 'my_val7' - 16 - '2010-07-03 01:01:01'

à la fin, je ne voudrais seulement 3 lignes, 1 avec un horodatage avec « 2010-07-01 01: 01:01 ', un avec' 2010-07-02 01:01:01 ', et un avec' 2010-07-03 01:01:01 '. le troisième est facile, puisqu'il n'y a qu'une seule ligne avec ce dernier horodatage. mais les deux premiers sont les plus délicats. le sql que j'ai posté ci-dessus ignorera la ligne avec 'my_val4'.

J'ai besoin d'une requête qui me renverra toutes les colonnes, pas seulement les dates. Comment devrais-je obtenir sql pour me donner la première ou la dernière des valeurs qui correspondraient à cet horodatage (peu importe d'une façon ou d'une autre, je dois juste obtenir une correspondance d'horodatage de 1 par jour)?

+0

Je ne comprends pas votre question. Votre requête existante semble renvoyer une seule ligne pour chaque date, même s'il y a plusieurs lignes par jour. Cela semble être ce que vous demandez. Cependant, vous avez également suggéré de joindre une autre table à la requête. Si vous rejoignez une autre table, vous devez inclure cette information dans votre question. – Mike

+0

Est-ce que mytable a un champ clé unique? –

+0

RE mark: oui, mytable a un champ clé unique (identifiant de transaction). RE mike: ma requête existante renvoie une seule ligne à chaque date. mais cette requête ne fournit que les premières insertions par jour. quand je rejoins la même table pour obtenir le reste des valeurs dans la table, je peux obtenir une situation plusieurs-à-un, où je peux avoir 10 inserts qui tombent tous sur un horodatage particulier. Je n'ai pas seulement besoin des dates du premier insert. J'ai aussi besoin de tout le reste dans la rangée. –

Répondre

4
select distinct on (date(my_timestamp)) * 
from my_table 
order by date(my_timestamp), my_timestamp 

Ce sélectionne toutes les colonnes, exactement une ligne par date(my_timestamp). La seule ligne par jour est la première ligne pour le groupe, comme déterminé par order by (donc c'est la ligne avec my_timestamp minime).

Bien sûr, vous pouvez ajouter tout ce dont vous avez besoin joins, wheres etc. Mais c'est le bout que vous cherchez.

+0

vous l'avez cloué. bien joué. solution très élégante. –

1

La solution consiste à utiliser instruction DISTINCT du SQL (http://www.sql-tutorial.com/sql-distinct-sql-tutorial/):

SELECT DISTINCT MIN(my_timestamp) AS first_timestamp FROM my_schema.my_table WHERE my_col1 = 'WHATEVER' AND my_timestamp > timestamp '2010-Jul-27 07:45:24' - INTERVAL '365 DAY' GROUP BY DATE (my_timestamp); 
+0

Je reçois déjà des lignes distinctes quand il s'agit de la date. dans votre sql ici, le mot clé 'distinct' ne fait rien (redondant). le 'groupe par' résout ce problème. il doit y avoir une jointure avec le SQL que j'ai donné ci-dessus, mais je ne sais pas quoi joindre pour obtenir ce que je veux. –

+0

le «groupe par» dans la requête aurait dû donner le fait que je n'ai pas besoin d'un distinct (http://stackoverflow.com/questions/426723/sql-group-by-versus-distinct), surtout compte tenu Je sélectionnais seulement 1 col (pourquoi utiliser un distinct & grouper sur une requête renvoyant seulement 1 col?). –

+0

Désolé, votre question a été mal comprise. Pourriez-vous préciser à quoi ressemble la table que vous voulez joindre à celle-ci? –

0

Je sais que vous avez déjà une réponse, mais je ne comprends toujours pas pourquoi vous avez mentionné une jointure dans votre question. Pourquoi ne pas simplement inclure le reste des colonnes dans votre requête, comme ceci:

SELECT MIN(my_timestamp) AS first_timestamp, my_col1, my_col2 
FROM my_table 
GROUP BY DATE(my_timestamp); 

Cela fonctionne en MySQL. Ne renvoie-t-il pas le résultat attendu dans PostgreSQL?

+0

no. 'GROUP BY' dans Postgres ne fonctionne pas de cette façon. Vous devez faire un 'Grouper par' pour chaque élément que vous essayez de sélectionner, ce qui signifie essentiellement que vous essayez de faire un "distinct" sur les 3 champs, ce qui n'est pas le résultat souhaité. merci pour l'entrée. –