2012-06-04 21 views
1

我有一個Postgres的表看起來像這樣一些數據:如何在Postgres中的其他兩行中生成新行?

1 apple datetime1 
2 orange datetime2 
3 apple datetime3 
4 orange datetime4 
5 apple datetime5 
6 orange datetime6 
. 

日期時間總是按升序排列,多數次蘋果行被插入第一和橙色的第二有一些例外,我要趕上並消除。

我實際上需要的是一個Postgres的查詢,將只配對蘋果和橘子:

1 apple datetime1 2 orange datetime2 
3 apple datetime3 4 orange datetime4 
5 apple datetime5 6 orange datetime6 

蘋果不應該與其他蘋果和桔子不應該與其他柑桔配對配對。

有幾個條件:

1)在新產生的行蘋果應始終是第一和第二橙色。

2)始終將蘋果和橙色行與最近的日期時間配對,並忽略其他行。

例如,如果我有原始數據看起來像這樣:

1 apple datetime1 
2 apple datetime2 
3 orange datetime3 
4 orange datetime4 

2 apple datetime2 3 orange datetime3 

,並忽略行

1 apple datetime1 
4 orange datetime4 

任何想法如何做到這一點的Postgres的?

+0

恰好兩個fuits - '蘋果'/'橙色'?沒有其他和沒有NULL? –

+0

@Erwin Brandstetter在同一張桌子上還有一些其他的水果,但爲了這份報告,我只需要找到蘋果和橙子配對。 – avatar

+0

@ErwinBrandstetter好的,這次你做CTE,好嗎? – wildplasser

回答

1

解決方案與CTE &窗函數:

WITH x AS (
    SELECT * 
      ,lead(tbl) OVER (ORDER BY id) AS y 
    FROM tbl 
    ) 
SELECT x.id,  x.fruit, x.dt 
    , (y).id, (y).fruit, (y).dt 
FROM x 
WHERE fruit = 'apple' 
AND (y).fruit = 'orange' 
ORDER BY x.id; 

可以做的子查詢一樣好,但每request from @wildplasser。 :)

我選擇整個「下一個」行每窗口功能lead()。請注意帶圓括號的語法來訪問組合(行)類型的列y

+0

我知道OP希望最近的時間戳上的匹配,而不是最接近的ID?但確實非常緊湊。 – wildplasser

+0

@wildplasser:同樣在這種情況下,因爲:'日期時間總是按升序排列'。 –

+0

就是這樣!非常感謝! – avatar

0
select 
    t0.id, t0.fruit, t0.datetime, 
    t1.id, t1.fruit, t1.datetime 
from t t0 
inner join t t1 on 
    t0.fruit = 'apple' 
    and 
    t1.fruit = 'orange' 
    and 
    t0.datetime < t1.datetime 
order by t1.datetime - t0.datetime 
limit 1 
0
SET search_path='lutser'; 

DROP TABLE fruits; 
CREATE TABLE fruits 
    (id INTEGER NOT NULL 
    , fruit varchar 
    , zdate varchar 
    ); 
INSERT INTO fruits(id,fruit,zdate) 
VALUES 

(1, 'apple', 'datetime01') 
, (2, 'orange', 'datetime02') 
, (3, 'apple', 'datetime03') 
, (4, 'orange', 'datetime04') 
, (5, 'apple', 'datetime05') 
, (6, 'orange', 'datetime06') 
, (11, 'apple', 'datetime11') 
, (12, 'apple', 'datetime12') 
, (13, 'orange', 'datetime13') 
, (14, 'orange', 'datetime14') 
    ; 

SELECT fa.id, fa.fruit, fa.zdate 
    , fo.id, fo.fruit, fo.zdate 
FROM fruits fa 
JOIN fruits fo ON fa.zdate < fo.zdate 
WHERE fa.fruit = 'apple' AND fo.fruit = 'orange' 
AND NOT EXISTS (
    SELECT * 
    FROM fruits nx 
    WHERE nx.fruit = 'orange' 
    AND nx.zdate > fa.zdate 
    AND nx.zdate < fo.zdate 
    ) 
AND NOT EXISTS (
    SELECT * 
    FROM fruits nx 
    WHERE nx.fruit = 'apple' 
    AND nx.zdate < fo.zdate 
    AND nx.zdate > fa.zdate 
    ) 
    ; 

結果:

DROP TABLE 
CREATE TABLE 
INSERT 0 10 
id | fruit | zdate | id | fruit | zdate  
----+-------+------------+----+--------+------------ 
    1 | apple | datetime01 | 2 | orange | datetime02 
    3 | apple | datetime03 | 4 | orange | datetime04 
    5 | apple | datetime05 | 6 | orange | datetime06 
12 | apple | datetime12 | 13 | orange | datetime13 
(4 rows) 
2

日期時間總是按升序排列,大部分時候蘋果行是先插入的,橙色的是第二次插入,但有一些例外,我必須趕上並消除。

如果我理解正確,你想要查找是否有任何兩個連續的行有相同的水果,對不對?

如果是這樣,你可以像這樣做:

WITH Q AS (
    SELECT *, ROW_NUMBER() OVER (ORDER BY datetime) R 
    FROM YOUR_TABLE 
) 
SELECT * 
FROM Q Q1 JOIN Q Q2 ON Q1.R = Q2.R - 1 
WHERE Q1.fruit = Q2.fruit; 

用簡單的英語:加入與下一個(其中的「下一個」的含義是由datetime排序確定的)每一行,並檢查他們的水果相配。你可以在這裏玩SQL Fiddle

順便說一句,這不是一個好的數據庫設計。你應該考慮重新設計,這樣上面描述的「無效」情況自然會被數據庫結構本身阻止。

+0

該OP非常清楚地表明,他希望'apple'後面跟着'orange'和* not *'連續兩行,同樣的水果'。 –

+0

@ErwinBrandstetter對於蘋果後面是橙色,它不能跟隨蘋果。他希望檢測到兩個連續的水果,所以他可以「消除」它們。我不清楚他是希望通過從表中刪除還是僅從查詢結果中刪除它們來消除它們 - 我的答案應該有助於前一種情況。 –

相關問題