2016-10-29 11 views
1

シェルからPostgreSQL v9.4.5を使用というデータベースを作成し、create database momentsを実行しました。私は、瞬間のテーブルを作成しました:大きなPostgreSQLクエリ出力カラムで使用するCTEサブクエリの出力の差を計算できません

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のフラグ値と、2番目に最近のタイムスタンプのフラグ値との差が返されるmp値を返し、結果をmoment_typeで昇順に表示します。

予想されるSQLクエリ出力

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

次のように私が思い付いたSQLクエリがある、で大きくSELECTクエリで一時テーブルとして使用するための複数のCommon Table Expressions (CET)サブクエリを書くためにWITHクエリを使用します終わり。私も(あるいは私が思うに、私はちょうどDIFFERENCEDIFFERENCE(most_recent_flag, second_most_recent_flag) AS flag関数の代わりに使用することもできます)サブクエリ出力の2の間の差を計算するためにSQL functionを使用します。

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; 

をしかし、私はPostgreSQLでは上記のSQLクエリを実行すると、それは次のエラーを返します。

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

質問を私が使用することができますし、私はTHIを克服するためにそれらをどのように適用される場合がありますどのような技術

エラーを計算し、flag列の相違点を計算して表示すると、のSQLクエリ出力が得られます

注:

答えて

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

一つの方法は、条件付き集約を使用することでテーブルの行を横切って計算を実行するようにおそらくWindow Functionを何とか使用することができます。 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; 
関連する問題