2016-08-05 17 views
0

我有一個包含一個表positions 此表如下:爲USER_ID由多個日期排序的一個結果

user_id | current | started_at | finished_at 
2  | false | 10-07-2016 | 02-08-2016 
1  | false | 19-07-2016 | 27-07-2016 
1  | true | 29-07-2016 | null 
3  | true | 20-07-2016 | null 
3  | false | 01-07-2016 | 18-07-2016 

我使用的情況下爲使用的started_atfinished_at日期取決於排序此表是否current是真還是假

SELECT * 
FROM positions 
ORDER BY 
    CASE 
     WHEN current = true 
      THEN started_at 
     ELSE finished_at 
    END 
DESC 

也能正常工作的期望,但現在我想只提取的第一行各user_id

所以在我的示例數據,我想只有有以下返回。

user_id | current | started_at | finished_at 
2  | false | 10-07-2016 | 02-08-2016 
1  | true | 29-07-2016 | null 
3  | true | 20-07-2016 | null 

我想這可能是與一個GROUP BY做,但我不能讓它沒有錯誤工作或也許我需要一個子查詢,我不知道。

+0

是「只有第一行」等於'WHERE current = true'嗎? – Razzka

+0

對不起,這是一個錯誤,修正 – Rob

回答

2

這是使用窗口函數的絕佳機會。您可以使用窗口函數來創建一個查詢,看起來像這樣:

SELECT user_id, current, started_at, finished_at, 
    row_number() OVER (PARTITION BY user_id) AS row_number 
    FROM positions 
    ORDER BY CASE WHEN current = true 
     THEN started_at ELSE finished_at END DESC 

這會給你與來自窗口功能的新列「ROW_NUMBER」你的原始表。您按user_id進行分區,因爲您想按用戶獲取row_number。使用你提供的ORDER子句。要獲得完整答案,只需使用此語句作爲子查詢,使用WHERE子句僅選擇row_number = 1,並提取所需的所有字段。窗口函數不能在WHERE子句中使用,這就是您需要子查詢的原因。

SELECT user_id, current, started_at, finished_at 
FROM 
(
SELECT user_id, current, started_at, finished_at, 
    row_number() OVER (PARTITION BY user_id) AS row_number 
FROM positions 
ORDER BY CASE WHEN current = true 
    THEN started_at ELSE finished_at END DESC 
) pos 
WHERE row_number= 1 
+0

此外 - 如果你是新的窗口功能,這裏是PostgreSQL的一些很好的文檔:[窗口功能(https://www.postgresql.org/docs/9.1/static/tutorial-window.html) – MattPerry

+0

感謝您的幫助,我喜歡這種方法。不幸的是它沒有給我預期的結果。結果不按日期列排序。它通過user_id命令http://pastebin.com/r5LkYXGC – Rob

+0

我明白你的意思了。我編輯答案將分類拉到分區外,並使用row_number()函數而不是rank()。如果您對同一個user_id具有完全相同的日期,Rank會給出重複的「1」值。我不知道你的完整數據集是否會有這個 - 但更安全。 – MattPerry

0

我猜你在你的例子犯了一個錯誤,因爲你想要的結果顯示一行user_id 1.

就可以輕鬆實現你想用非標準的PostgreSQL DISTINCT ON特點是什麼:

SELECT DISTINCT ON (user_id) * FROM 
    (SELECT * FROM positions 
    ORDER BY 
     CASE 
      WHEN current = true 
      THEN started_at 
      ELSE finished_at 
     END 
    DESC) q; 

這將刪除所有,但第一排的每個user_id

+0

這是第一排由我的例子中,預期的結果是正確的日期排序。不幸的是你的答案錯誤「SELECT DISTINCT ON表達式必須匹配初始ORDER BY表達式」 – Rob

+0

確實,對不起。我編輯了答案。 –

+0

感謝您的幫助@ laurenz-ALBE不幸的是,結果數據集不是由作爲唯一的內選擇的排序情況下使用的日期排序。我現在有一個來自Matt的工作版本。感謝您的輸入! – Rob