2009-02-25 5 views
2

J'ai une base de données Informix contenant des valeurs de température mesurées pour un certain nombre d'emplacements différents. Les mesures sont prises toutes les 15 minutes pour tous les emplacements, puis chargées avec un horodatage dans la même table. Le tableau ressemble à ceci:SQL pour trouver la différence entre deux lignes

 
locId dtg    temp 
aaa  2009-02-25 10:00 15 
bbb  2009-02-25 10:00 20 
ccc  2009-02-25 10:00 24 
aaa  2009-02-25 09:45 13 
ccc  2009-02-25 09:45 16 
bbb  2009-02-25 09:45 18 
ddd  2009-02-25 09:45 12 
aaa  2009-02-25 09:30 11 
ccc  2009-02-25 09:30 14 
bbb  2009-02-25 09:30 15 
ddd  2009-02-25 09:30 10 

Maintenant, je voudrais une requête qui me présente avec le changement de température entre les deux dernières mesures pour toutes les stations. Et aussi, seulement ceux qui ont une mesure mise à jour. Par exemple dans le tableau ci-dessus, l'emplacement ddd ne serait pas inclus. Ainsi, le résultat devient:

 
locId change 
aaa  2 
bbb  2 
ccc  8 

J'ai essayé beaucoup, mais je ne peux pas trouver une bonne solution. En réalité, c'est environ 700 sites qui sont demandés à partir d'une page Web, donc je pense que la requête doit être assez efficace.

J'apprécierais vraiment de l'aide!
// Jesper

+0

Pourquoi ne pas inclure ddd? Il a une entrée à 9h30 avec temp de 10, et une autre entrée à 9h45 avec temp de 12. – jimmyorr

+0

seule station avec des données à 10h00 et 09h45 doivent être inclus – BCS

Répondre

4
set now = select max(dtg) from table; 
set then = select max(dtg) from table where dtg < now; 

select locID, old.temp-new.temp from 
     table as old join 
     table as new 
     on old.locId = new.locID 
where 
     old.dtg = then and 
     new.dtg = now; 

suppose que tous les temps seront exacts

+0

Par "tous les temps seront exactes "Je pense que ce code suppose que les deux dernières lectures pour tous les emplacements seront exactement au même moment. Cela semble improbable. Aussi pourrait vouloir modifier le "Ware" à "Où" – JohnFx

+0

qui dépend de la façon dont les choses sont configurées. cela pourrait facilement se produire dans un modèle de traction. – BCS

+0

True. Je voulais juste m'assurer que le PO comprenait que cela ne fonctionnerait que dans ce scénario. – JohnFx

2

Dans pseudo-SQL, vous pouvez faire la requête:

@now = Time Now 

Select Oldest.LocId, Oldest.timestamp, Oldest.temp - Newest.temp as Change 
(Select LocId, temp from Foo where timestamp < @now - 15 mins AND timestamp >= @now - 30 mins) Oldest 
    left join 
(Select LocId, temp from Foo where timestamp >= TimeNow - 15 mins) Newest 
    on Oldest.LocId = Newest.LocId 

Je ne sais pas si vous définissez cela comme une solution « bonne », mais il faut travailler à condition qu'il existe deux points de données pour chaque emplacement.

1
declare @dt_latest datetime, @dt_prev datetime 

select @dt_latest = max(dtg) from Measures 
select @dt_prev = max(dtg) from Measures where dtg < @dt_latest 

select Latest.Locid, Latest.temp - Prev.temp 
from Measures as "Latest" 
inner join Measures as "Prev" on Latest.Locid = Prev.Locid 
where Latest.dtg = @dt_latest 
and Prev.dtg = @dt_prev 

Edit: même que BCS essentiellement, me battre pour elle!

0

Essayez quelque chose comme ceci. Il ne peut pas être super efficace, mais contrairement à certains des autres réponses, il retournera la dif pour chaque Locid

SELECT DISTINCT LocID, 
      (SELECT max(t3.temp)-min(t3.temp) from 
        (SELECT TOP 2 T2.temp 
        From Table2 T2 
        Where (t2.Locid=t1.locid) 
        order by DTG DESC) as t3 
      ) as Diff 
    FROM Table1 T1 

caveat: J'ai écrit cela en utilisant Tsql, mais essayé de coller à la norme SQL ANSI, autant que possible portabilité à Informix.

1

Je ne crois pas que Informix ait des fonctions analytiques comme Oracle, mais si c'était le cas, ce serait un excellent endroit pour les utiliser. Ce qui suit est un exemple Oracle utilisant les fonctions analytiques lag et max.

script d'installation:

drop table temps; 
create table temps (
locId varchar2(3), 
dtg date, 
temp number(3) 
); 

insert into temps values ('aaa', to_date('2009-02-25 10:00','yyyy-mm-dd hh:mi'), 15); 
insert into temps values ('bbb', to_date('2009-02-25 10:00','yyyy-mm-dd hh:mi'), 20); 
insert into temps values ('ccc', to_date('2009-02-25 10:00','yyyy-mm-dd hh:mi'), 24); 
insert into temps values ('aaa', to_date('2009-02-25 09:45','yyyy-mm-dd hh:mi'), 13); 
insert into temps values ('ccc', to_date('2009-02-25 09:45','yyyy-mm-dd hh:mi'), 16); 
insert into temps values ('bbb', to_date('2009-02-25 09:45','yyyy-mm-dd hh:mi'), 18); 
insert into temps values ('ddd', to_date('2009-02-25 09:45','yyyy-mm-dd hh:mi'), 12); 
insert into temps values ('aaa', to_date('2009-02-25 09:30','yyyy-mm-dd hh:mi'), 11); 
insert into temps values ('ccc', to_date('2009-02-25 09:30','yyyy-mm-dd hh:mi'), 14); 
insert into temps values ('bbb', to_date('2009-02-25 09:30','yyyy-mm-dd hh:mi'), 15); 
insert into temps values ('ddd', to_date('2009-02-25 09:30','yyyy-mm-dd hh:mi'), 10); 
commit; 

requêtes spécifiques Oracle en utilisant des fonctions analytiques:

select locId, change 
    from (
select t.locId, 
     t.dtg, 
     t.temp, 
     -- difference between this records temperature and the record before it 
     t.temp - lag(t.temp) over (partition by t.locId order by t.dtg) change, 
     -- max date for this location 
     max(t.dtg) over (partition by t.locId) maxDtg, 
     max(t.dtg) over (partition by 1) overallMaxDtg 
    from temps t 
order by t.locId, t.dtg 
) where maxDtg = dtg -- only most recent measurement 
    and overallMaxDtg = maxDtg -- only stations with an 'updated measurement' 
    ; 

Résultat:

LOCID CHANGE 

aaa 2 
bbb 2 
ccc 8 

Bonne ressource sur l'analyse Oracle: http://www.psoug.org/reference/analytic_functions.html

4

Merci à uglysmurf de fournir les données dans un format SQL. En utilisant la version 11.50 de IDS (IBM Informix Dynamic Server), la requête suivante fonctionne.

CREATE TEMP TABLE temps 
(
    locId CHAR(3), 
    dtg  DATETIME YEAR TO MINUTE, 
    temp SMALLINT 
); 
INSERT INTO temps VALUES ('aaa', '2009-02-25 10:00', 15); 
INSERT INTO temps VALUES ('bbb', '2009-02-25 10:00', 20); 
INSERT INTO temps VALUES ('ccc', '2009-02-25 10:00', 24); 
INSERT INTO temps VALUES ('aaa', '2009-02-25 09:45', 13); 
INSERT INTO temps VALUES ('ccc', '2009-02-25 09:45', 16); 
INSERT INTO temps VALUES ('bbb', '2009-02-25 09:45', 18); 
INSERT INTO temps VALUES ('ddd', '2009-02-25 09:45', 12); 
INSERT INTO temps VALUES ('aaa', '2009-02-25 09:30', 11); 
INSERT INTO temps VALUES ('ccc', '2009-02-25 09:30', 14); 
INSERT INTO temps VALUES ('bbb', '2009-02-25 09:30', 15); 
INSERT INTO temps VALUES ('ddd', '2009-02-25 09:30', 10); 

SELECT latest.locID, latest.temp, prior.temp, 
     latest.temp - prior.temp as delta_temp, 
     latest.dtg, prior.dtg 
    FROM temps latest, temps prior 
    WHERE latest.locId = prior.locId 
     AND latest.dtg = prior.dtg + 15 UNITS MINUTE 
     AND latest.dtg = (SELECT MAX(dtg) FROM temps); 

résultats (plus de colonnes que demandé, mais vous pouvez facilement découper la liste de sélection):

aaa 15 13 2 2009-02-25 10:00 2009-02-25 09:45 
ccc 24 16 8 2009-02-25 10:00 2009-02-25 09:45 
bbb 20 18 2 2009-02-25 10:00 2009-02-25 09:45 

Notez que cette solution ne dépend pas de courant (ou NOW); cela fonctionne sur les dernières données enregistrées. La seule partie de l'instruction SELECT qui est spécifique à l'IDS est le '+ 15 UNITS MINUTE'; cela pourrait également être écrit comme '+ INTERVAL(15) MINUTE TO MINUTE' dans Informix, et comme '+ INTERVAL '15' MINUTE' dans SQL standard (si le SGBD supporte les types INTERVAL). L'utilisation de DATETIME YEAR TO MINUTE dans la table est spécifique à Informix; Dans un contexte comme celui-ci, il est utile de ne pas stocker les informations qui ne vous intéressent pas (comme les secondes).

+1

Sans analyse, je préfère cette solution SQL uniquement, par opposition à BCS qui utilise trois requêtes distinctes et des variables temporaires ... totalement inutile. – jimmyorr

+0

Un conseil pour Jonathan Leffler: utilisez des alias de table plus descriptifs. "new" et "old" donnent plus d'informations que "a" et "b". Pour plus de lisibilité, je réarrangerais aussi un peu les prédicats, de sorte que "old.dtg = new.dtg - 15 ...", et "new.dtg = (SELECT MAX ...)". De cette façon, il est clair ce que sont les anciens et les nouveaux dtg. – jimmyorr

+1

@uglysmurf: Juste commentaire; Je vais modifier en conséquence. Pour le travail d'essai, j'utilise des alias courts - je ne suis simplement pas passé en mode 'non-trial'. –