1

Использование PostgreSQL v9.4.5 из Shell Я создал базу данных, называемую моментами в psql, запустив create database moments. Затем я создал моменты таблицу:Невозможно рассчитать разницу между выходами подзапроса CTE для использования в более крупном столбце вывода запроса PostgreSQL

CREATE TABLE moments 
(
    id SERIAL4 PRIMARY KEY, 
    moment_type BIGINT NOT NULL, 
    flag BIGINT NOT NULL, 
    time TIMESTAMP NOT NULL, 
    UNIQUE(moment_type, time) 
); 
INSERT INTO moments (moment_type, flag, time) VALUES (1, 7, '2016-10-29 12:00:00'); 
INSERT INTO moments (moment_type, flag, time) VALUES (1, -30, '2016-10-29 13:00:00'); 
INSERT INTO moments (moment_type, flag, time) VALUES (3, 5, '2016-10-29 14:00:00'); 
INSERT INTO moments (moment_type, flag, time) VALUES (2, 9, '2016-10-29 18:00:00'); 
INSERT INTO moments (moment_type, flag, time) VALUES (2, -20, '2016-10-29 17:00:00'); 
INSERT INTO moments (moment_type, flag, time) VALUES (3, 10, '2016-10-29 16:00:00'); 

Я бегу select * from moments для просмотра таблицы:

Моменты Таблица

id | moment_type | flag |  time   
----+-------------+------+--------------------- 
    1 |   1 | 7 | 2016-10-29 12:00:00 
    2 |   1 | -30 | 2016-10-29 13:00:00 
    3 |   3 | 5 | 2016-10-29 14:00:00 
    4 |   2 | 9 | 2016-10-29 18:00:00 
    5 |   2 | -20 | 2016-10-29 17:00:00 
    6 |   3 | 10 | 2016-10-29 16:00:00 

Затем я пытаюсь написать запрос SQL, который производит следующий вывод , в результате чего для каждой пары повторяющихся значений параметра moment_type она возвращает разность между значением флага параметра moment_type, имеющим самое последнее значение временной метки, и значением флага второй самой последней timesta mp, и перечисляет результаты в порядке возрастания по типу момента.

Ожидаемый результат SQL-запроса

moment_type | flag | 
------------+------+ 
      1 | -37 | (i.e. -30 - 7) 
      2 | 29 | (i.e. 9 - -20) 
      3 | 5 | (i.e. 10 - 5) 

SQL-запрос, который я придумал это следующим образом, который использует С запросом, чтобы написать несколько Common Table Expressions (CET) подзапросов для использования в качестве временных таблиц в большем запросе на выборку в конец. Я также использовать SQL function вычислить разницу между двумя подзапросов выходов (в качестве альтернативы я думаю, что я мог бы просто использовать DIFFERENCEDIFFERENCE(most_recent_flag, second_most_recent_flag) AS flag вместо функции):

CREATE FUNCTION difference(most_recent_flag, second_most_recent_flag) RETURNS numeric AS $$ 
    SELECT $1 - $2; 
$$ LANGUAGE SQL; 

-- get two flags that have the most recent timestamps 
WITH two_most_recent_flags AS (
SELECT moments.flag 
FROM moments 
ORDER BY moments.time DESC 
LIMIT 2 
), 
-- get one flag that has the most recent timestamp 
most_recent_flag AS (
SELECT * 
FROM two_most_recent_flags 
ORDER BY flag DESC 
LIMIT 1 
), 
-- get one flag that has the second most recent timestamp 
second_most_recent_flag AS (
SELECT * 
FROM two_most_recent_flags 
ORDER BY flag ASC 
LIMIT 1 
) 
SELECT DISTINCT ON (moments.moment_type) 
moments.moment_type, 
difference(most_recent_flag, second_most_recent_flag) AS flag 
FROM moments 
ORDER BY moment_type ASC 
LIMIT 2; 

Но когда я запускаю выше запрос SQL в PostgreSQL, он возвращает следующую ошибку:

ERROR: column "most_recent_flag" does not exist 
LINE 21: difference(most_recent_flag, second_most_recent_flag) AS fla... 

Вопрос

Какие методы можно использовать и как я могу использовать их, чтобы преодолеть Тхи s и вычислять и отображать различия в столбце flag для достижения Ожидаемый вывод SQL-запроса?

Примечание: Возможно, Window Function может быть использован каким-то образом, как он выполняет вычисления всей строки таблицы

ответ

1

Используйте функцию lag() окна:

select moment_type, difference 
from (
    select *, flag- lag(flag) over w difference 
    from moments 
    window w as (partition by moment_type order by time) 
    ) s 
where difference is not null 
order by moment_type 

moment_type | difference 
-------------+------------ 
      1 |  -37 
      2 |   29 
      3 |   5 
(3 rows)  
1

Один из способов заключается в использовании условной агрегации. Функция окна row_number() может быть использована для идентификации первого и последнего значения времени:

select m.moment_type, 
     (max(case when seqnum_desc = 1 then flag end) - 
     min(case when seqnum_asc = 1 then flag end) 
     ) 
from (select m.*, 
      row_number() over (partition by m.moment_type order by m.time) as seqnum_asc, 
      row_number() over (partition by m.moment_type order by m.time desc) as seqnum_desc 
     from moments m 
    ) m 
group by m.moment_type; 

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

  • Нет связанных вопросов^_^