2011-07-07 71 views
4

我有以下簡化的數據表:SQL與COALESCE或窗函數過濾

PK FK Type 
---------------- 
1  11 A 
2  11 B 
3  12 B 
4  13 C 
5  13 D 
6  14 D 

而且我希望有一個結果集:

PK FK Type 
--------------- 
1  11 A 
3  12 B 
4  13 C 
6  14 D 

所以如果一個給定的FK值具有類型A,不要給我任何行,B,C或D.或者如果該值具有類型B,則過濾出C和D等。這感覺就像我需要應用窗口函數或合併,但我不知道該怎麼做。

+0

TSQL如在Sybase或SQL Server? –

+1

所以你不清楚,你的意思是說,如果它的值爲W,那麼只能濾除X,Y和Z?這是否意味着允許在A-V?但是,如果存在這些較低值中的任何一個,那麼這是否也意味着你濾除了低於該較低值的一切?這將等於讓所有的值都等於存在的字母表中的最低字母,並且沒有其他值... –

+0

我正在使用SQL Server。在我看來,這些值有優先權,所以如果有一個A,那麼就返回那個,否則如果有一個B,就返回那個,等等。每個FK值只返回一行,那個具有最高優先級的行類型值。 – swandog

回答

4

用途:

SELECT x.* 
    FROM (SELECT s.*, 
       ROW_NUMBER() OVER(PARTITION BY s.fk 
            ORDER BY s.pk) rnk 
      FROM YOUR_TABLE s) x 
WHERE x.rnk = 1 

...或使用CTE(沒有性能上的差異):

WITH example AS (
    SELECT s.*, 
     ROW_NUMBER() OVER(PARTITION BY s.fk 
           ORDER BY s.pk) rnk 
    FROM sample s) 
SELECT x.* 
    FROM example x 
WHERE x.rnk = 1 

證明:

WITH sample AS (
    SELECT 1 AS PK, 11 AS FK, 'A' AS [TYPE] 
    UNION ALL 
    SELECT 2 AS PK, 11 AS FK, 'B' AS [TYPE] 
    UNION ALL 
    SELECT 3 AS PK, 12 AS FK, 'B' AS [TYPE] 
    UNION ALL 
    SELECT 4 AS PK, 13 AS FK, 'C' AS [TYPE] 
    UNION ALL 
    SELECT 5 AS PK, 13 AS FK, 'D' AS [TYPE] 
    UNION ALL 
    SELECT 6 AS PK, 14 AS FK, 'D' AS [TYPE]) 
SELECT x.* 
    FROM (SELECT s.*, ROW_NUMBER() OVER(PARTITION BY s.fk 
              ORDER BY s.pk) rnk 
      FROM sample s) x 
WHERE x.rnk = 1 

結果:

pk fk type 
---------------- 
1 11 A 
3 12 B 
4 13 C 
6 14 D 
+0

很好用,現在我已經開始關注窗口函數了。謝謝。 – swandog

+0

實際上,如果數據中包含「PK」和「FK」不匹配的順序,這不會完全失敗嗎?例如,如果您在數據中切換行1和2,您仍然應該爲該行返回類型「A」......但由於1是最小的「PK」,因此此解決方案返回類型「B」 ... –

+0

換句話說,我想你可以通過執行'ORDER BY s.Type'而不是'ORDER BY s.pk'來修復它。我認爲這很重要。 –

1

因此,對於每個FK值,您想要匹配的最小PK值以及PK的相應類型?一如既往,一步一步做。

哪些是我們想要的PK值?

SELECT FK, MIN(PK) AS PK 
    FROM SimplifiedData 
GROUP BY FK 

如何獲得相應的行 - 爲什麼,加入與主表,當然:

SELECT S.PK, S.FK, S.Type 
    FROM SimplifiedData AS S 
    JOIN (SELECT FK, MIN(PK) AS PK 
      FROM SimplifiedData 
     GROUP BY FK 
     ) AS T ON S.PK = T.PK 
ORDER BY S.FK;