2016-03-03 38 views
0

我有一個包含日期和結果的已發送電子郵件的大型單表,我希望能夠匹配上一次發送電子郵件和發生特定結果的每一行(此處打開= 1)。這需要用PostgreSQL完成。例如:PostgreSQL按最近日期加入兩張表

初始表:

id | sent_dt  | bounced | open ` | clicked | unsubscribe 
1 | 2015-01-01 | 1   |  0 | 0  | 0 
1 | 2015-01-02 | 0   |  1 | 1  | 0 
1 | 2015-01-03 | 0   |  1 | 1  | 0 
2 | 2015-01-01 | 0   |  1 | 0  | 0 
2 | 2015-01-02 | 1   |  0 | 0  | 0 
2 | 2015-01-03 | 0   |  1 | 0  | 0 
2 | 2015-01-04 | 0   |  1 | 0  | 1 

結果表:

id | sent_dt  | bounced| open | clicked | unsubscribe| previous_time 
1 | 2015-01-01 | 1  | 0 | 0   | 0   | NULL 
1 | 2015-01-02 | 0  | 1 | 1   | 0   | NULL 
1 | 2015-01-03 | 0  | 1 | 1   | 0   | 2015-01-02 
2 | 2015-01-01 | 0  | 1 | 0   | 0   | NULL 
2 | 2015-01-02 | 1  | 0 | 0   | 0   | 2015-01-01 
2 | 2015-01-03 | 0  | 1 | 0   | 0   | 2015-01-01 
2 | 2015-01-04 | 0  | 1 | 0   | 1   | 2015-01-03 

我一直在使用Lag嘗試,但我不知道如何去與條件打開時需要等於1,同時仍然返回所有行。我也嘗試在id上多做多Join,然後找到最低Datediff,但這基本上是我桌子的大小的平方,並且需要很長的時間來計算(> 7小時)。有幾個答案適用於SQL,但我沒有看到PostgreSQL的工作。

感謝您的幫助!

+0

有一個特殊的'FILTER'原因,您可以用窗口函數使用像'滯後()':HTTP:// WWW .postgresql.org/docs/current/static/sql-expressions.html#SYNTAX-WINDOW-FUNCTIONS –

+0

@IgorRomanchenko'FILTER'只適用於9.4+ isnt嗎? –

回答

0

您可以使用ROW_NUMBER()來實現這一期望的結果,每一個連接到它是否有開放= 1

SELECT t.*,s.sent_dt 
FROM 
     (SELECT p.*, 
       ROW_NUMBER() OVER(PARTITION BY ID ORDER BY sent_dt DESC) rnk 
     FROM YourTable p) t 
LEFT OUTER JOIN 
    (SELECT p.*, 
      ROW_NUMBER() OVER(PARTITION BY ID ORDER BY sent_dt DESC) rnk 
     FROM YourTable p) s 
ON(t.rnk = s.rnk-1 AND s.open = 1) 
+0

如果我抓住沒有條件的表格的行號和表格的行號在open = 1的情況下,他們會不會完全排隊?我想我可以使用這種方法,但是我不得不做一些我相信的修改。 Nvm - 我看你做了什麼。 – Jason

+0

什麼?..這應該完美適合你.. @Jason – Yossi

+0

我道歉,我沒有看到最後的條件,直到我寫我的評論。我現在正在運行它,並會回到它是否工作。感謝您的幫助@Yossi – Jason

0

首先我創建日期的CTE openFilter發生前的一個,其中郵件已打開。

然後我加入表格郵件和那些過濾器,並獲得該電子郵件之前的日期。最後,過濾每個人都會刪除最新的公開郵件。

SQL Fiddle Demo

WITH openFilter as (
    SELECT m."id", m."sent_dt" 
    FROM mail m 
    WHERE "open" = 1 
) 
SELECT m."id", 
     to_char(m."sent_dt", 'YYYY-MM-DD'), 
     "bounced", "open", "clicked", "unsubscribe", 
     to_char(o."sent_dt", 'YYYY-MM-DD') previous_time 
FROM mail m 
LEFT JOIN openFilter o 
     ON m."id" = o."id" 
     AND m."sent_dt" > o."sent_dt"  
WHERE o."sent_dt" = (SELECT MAX(t."sent_dt") 
        FROM openFilter t 
        WHERE t."id" = m."id" 
         AND t."sent_dt" < m."sent_dt") 
    OR o."sent_dt" IS NULL 

輸出

| id | to_char | bounced | open | clicked | unsubscribe | previous_time | 
|----|------------|---------|------|---------|-------------|---------------| 
| 1 | 2015-01-01 |  1 | 0 |  0 |   0 |  (null) | 
| 1 | 2015-01-02 |  0 | 1 |  1 |   0 |  (null) | 
| 1 | 2015-01-03 |  0 | 1 |  1 |   0 | 2015-01-02 | 
| 2 | 2015-01-01 |  0 | 1 |  0 |   0 |  (null) | 
| 2 | 2015-01-02 |  1 | 0 |  0 |   0 | 2015-01-01 | 
| 2 | 2015-01-03 |  0 | 1 |  0 |   0 | 2015-01-01 | 
| 2 | 2015-01-04 |  0 | 1 |  0 |   1 | 2015-01-03 |