2009-02-25 2 views
2

У меня есть база данных Informix, содержащая измеренные значения температуры для целого ряда разных местоположений. Измерения берутся каждые 15 минут для всех местоположений, а затем загружаются меткой времени в ту же таблицу. Таблица выглядит следующим образом:SQL, чтобы найти разницу между двумя строками

 
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 

Теперь я хотел бы запрос, представить меня с изменением температуры между двумя последними измерениями для всех станций. А также, только те, которые имеют обновленное измерение. Например, в приведенной выше таблице местоположение ddd не будет включено. Таким образом, результат становится:

 
locId change 
aaa  2 
bbb  2 
ccc  8 

Я пытался много, но я не могу найти хорошее решение. На самом деле это около 700 мест, которые запрашиваются с веб-страницы, поэтому я считаю, что запрос должен быть достаточно эффективным.

Поблагодарили бы за помощь!
// Jesper

+0

Почему бы не включить ddd? Он имеет вход в 9:30 с температурой 10 и еще одну запись в 9:45 с временным номером 12. – jimmyorr

+0

только станция с данными в 10:00 и 9:45 должна быть включена – BCS

ответ

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; 

предполагает, что все время будет точно

+0

«Все время будет точным «Я думаю, что этот код предполагает, что последние два чтения для всех местоположений будут в одно и то же время друг с другом. Кажется маловероятным. Также может потребоваться отредактировать «Ware» до «Where» – JohnFx

+0

, что зависит от того, как настроены настройки. это может легко произойти в модели тянуть. – BCS

+0

Правда. Я просто хотел убедиться, что ОП понял, что он будет работать только в этом сценарии. – JohnFx

2

В псевдо-SQL вы можете сделать запрос:

@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 

Не уверен, если вы определили это как «хорошее» решение, но оно должно работать при условии есть две точки данных для каждое место.

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: так же, как BCS в основном, бить меня к нему!

0

Дайте что-нибудь вроде этого попробовать. Это может быть не очень эффективным, но в отличие от некоторых других ответов он будет возвращать диф для каждого 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 

Оговорка: Я написал это, используя TSQL, но старался придерживаться стандартного ANSI SQL, насколько это возможно переносимость Informix.

1

Я не верю, что Informix имеет такие аналитические функции, как Oracle, но если бы это было сделано, это было бы отличным местом для их использования. Далее следует пример Oracle, использующий аналитические функции lag и max.

скрипт установки:

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; 

Oracle конкретных запросов, используя аналитические функции:

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' 
    ; 

Результат:

LOCID CHANGE 

aaa 2 
bbb 2 
ccc 8 

Хороший ресурс на аналитика Oracle: http://www.psoug.org/reference/analytic_functions.html

4

Благодаря uglysmurf для предоставления данных в формате SQL.

Используя IDS (IBM Informix Dynamic Server) версии 11.50, работает следующий запрос.

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); 

Результаты (больше столбцов, чем требуется, но вы можете легко обрезать список выбора):

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 

Обратите внимание, что это решение не зависит от тока (или NOW); он работает с последними записанными данными. Единственной частью оператора SELECT, специфичным для IDS, является «+ 15 UNITS MINUTE»; который также может быть записан как «+ INTERVAL(15) MINUTE TO MINUTE» в Informix и как «+ INTERVAL '15' MINUTE» в стандартном SQL (если СУБД поддерживает типы INTERVAL). Использование DATETIME YEAR TO MINUTE в таблице является Informix-специфичным; в таком контексте полезно не хранить информацию, которая вам не интересна (например, секунды).

+1

Без аналитики я предпочитаю это решение только для SQL, в отличие от BCS, которое использует три отдельных запроса и временные переменные ... совершенно ненужно. – jimmyorr

+0

Один совет для Джонатана Леффлера: используйте более описательные псевдонимы таблиц. «новые» и «старые» дают больше информации, чем «а» и «б». Для удобства чтения я также немного изменил бы предикаты, чтобы «old.dtg = new.dtg - 15 ...» и «new.dtg = (SELECT MAX ...)». Таким образом, понятно, что такое старые и новые dtg. – jimmyorr

+1

@uglysmurf: справедливый комментарий; Я отредактирую соответственно. Для пробной работы я использую короткие псевдонимы - я просто не перешел в режим «без суда». –

Смежные вопросы