2016-05-07 3 views
1

窓関数/部分的な表での参加問題のPostgreSQL:

私は、データベース内のカーネルでプロジェクトを働いている、と私のPostgreSQLのスキルは壁を直撃しています。 2つの表を結合して、クロス積を計算しています。すなわち、

SELECT (d1.a * d2.a + d1.b * d2.b) AS dot FROM data d1, data d2 

これは、すべてのベクトルの間にクロス積を与えます。私のテーブルに以下のデータを持つ

a | b | c 
---+---+--- 
1 | 1 | 1 
2 | 2 | 2 
3 | 3 | 3 

上記のコマンド利回り

dot 
----- 
    2 
    4 
    6 
... 

私はその前の行とその次の行と行2、たとえば、間の内積を計算したい場合は、どのように私はそれを効率的にしますか?

試み

私は、ウィンドウ関数を使用しようとしましたが、彼らは唯一の集約関数を計算するので、これを行うに失敗しています。隣接する行(つまりそのウィンドウ)と行を結合したいが、それらの上の集約は計算しない。これらの線に沿ったもの:

SELECT a * a + b * b + c * c 
    OVER(rows between 1 preceding and 1 following) as value FROM data data; 

私はまた、row_number() OVER()を使用しようとしました。しかし、ネストされたサブクエリでは、これは不便で非効率です。

SELECT d1.a * d3.a + d1.b * d3.b + d1.c * d3.c 
    FROM data d1, 
    (SELECT * FROM 
     (SELECT *, row_number() OVER() as index from data) d2 
    WHERE d2.index >= 1 AND d2.index <=3) d3; 

最後に、私は運でLATERALの掘り下げてみました。

どのような考えですか?

+0

:行の順序がaによって決定された場合
、クエリは次のようになります。 SQLにはそのような構造の概念はありません。また、サンプルの結果は、達成したいことを説明するのに役立ちます。 –

+0

'...前の行と次の行との間で、たとえば2行目と2行目の間にドットプロダクトを計算します。「先行する*と*続く*を定義してください。 (* order *を定義し、あなたの問題は解決されます)BTW:あなたのテーブルは主キーを持っていますか? – wildplasser

+0

この例では、 'a'列に対して任意の順序があるとします。どうやって、それ自身とn個の隣接する行との間で結合を行うのですか? –

答えて

0

前/後の行の値をlag()/lead()で取得できます。あなたは、先行して次を定義する必要があり

SELECT 
    a, 
    (lag(a, 1, 0) OVER (ORDER BY a)) * (lead(a, 1, 0) OVER (ORDER BY a)) 
    + (lag(b, 1, 0) OVER (ORDER BY a)) * (lead(b, 1, 0) OVER (ORDER BY a)) 
    + (lag(c, 1, 0) OVER (ORDER BY a)) * (lead(c, 1, 0) OVER (ORDER BY a)) AS dot_preceding_and_following 
FROM (VALUES 
    (1, 1, 1), 
    (2, 2, 2), 
    (3, 3, 3) 
) T(a, b, c) 
ORDER BY 
    a 
;