2017-06-15 43 views
1

我已經看過其他答案,但我無法將答案應用到我的應用程序。我有一個返回類似的查詢如下:每組最大的n,同時還返回內容

SELECT * 
FROM MYTABLE T; 

__________________________________________________________ 
| ID | AORB |  ....OTHER (UNIQUE) CONTENT.....  | 
|---------------------------------------------------------| 
| 1 | A |  ....CONTENT       | 
| 1 | B |  ....CONTENT       | 
| 2 | A |  ....CONTENT       | 
| 3 | A |  ....CONTENT       | 
| 3 | B |  ....CONTENT       | 
| 4 | A |  ....CONTENT       | 
| 5 | B |  ....CONTENT       | 
| 6 | A |  ....CONTENT       | 
| 6 | B |  ....CONTENT       | 
----------------------------------------------------------- 

正如你所看到的,也有偶爾與相同ID但不同的內容最多兩行和A或B的AORB有時有一個「唯一」ID爲1,AORB可以是AB

只是爲了使數據結構清晰,你可以通過 'AORB' 過濾如下起來拆表:

所有A的:

SELECT * 
FROM MYTABLE T 
WHERE T.AORB = 'A'; 

__________________________________________________________ 
| ID | AORB |  ....OTHER (UNIQUE) CONTENT.....  | 
|---------------------------------------------------------| 
| 1 | A |  ....CONTENT       | 
| 2 | A |  ....CONTENT       | 
| 3 | A |  ....CONTENT       | 
| 4 | A |  ....CONTENT       | 
| 6 | A |  ....CONTENT       | 
---------------------------------------------------------- 

所有B的:

SELECT * 
FROM MYTABLE T 
WHERE T.AORB = 'B'; 

__________________________________________________________ 
| ID | AORB |  ....OTHER (UNIQUE) CONTENT.....  | 
|---------------------------------------------------------| 
| 1 | B |  ....CONTENT       | 
| 3 | B |  ....CONTENT       | 
| 5 | B |  ....CONTENT       | 
| 6 | B |  ....CONTENT       | 
----------------------------------------------------------- 

我需要一個類似於以下內容的查詢,但將所有其他內容行返回到右側:

SELECT ID, MIN(AORB) 
FROM MYTABLE T 
GROUPBY ID; 

我的要求是,如果有兩行具有相同的ID,返回行。如果給定ID只有一行,則返回該行,而不管AORB

我試着做了a和b的查詢都不過的UNION由於內容是不同的,但它仍然會返回「重複」的ID:

SELECT * 
FROM MYTABLE T 
WHERE T.AORB = 'B' 
UNION 
SELECT * 
FROM MYTABLE T 
WHERE T.AORB = 'A'; 

回答

1

我想這是你想要什麼:

SELECT T.* 
FROM MYTABLE T 
WHERE T.AORB = 'A' UNION ALL 
SELECT T.* 
FROM MYTABLE T 
WHERE T.AORB = 'B' AND 
     NOT EXISTS (SELECT 1 FROM MYTABLE T2 WHERE T2.ID = T.ID AND T2.AORB = 'A'); 

這是一個優先級查詢。它返回所有「A」。如果沒有相應的「A」,則全部爲「B」。

+0

這真的很棒,它正是我所需要的。我用'WITH'替換了MYTABLE,因爲我的實際查詢要複雜得多。 –

1

您可以使用row_number來優先處理order by中的條件。

SELECT * FROM (
SELECT T.*, ROW_NUMBER() OVER(PARTITION BY T.ID ORDER BY CASE WHEN T.AORB = 'A' THEN 1 ELSE 2 END) AS RNUM 
FROM MYTABLE T 
) T 
WHERE RNUM=1 

如果AORB值只有A,B的查詢可以簡化爲

SELECT * FROM (
SELECT T.*, ROW_NUMBER() OVER(PARTITION BY T.ID ORDER BY T.AORB) AS RNUM 
FROM MYTABLE T 
) T 
WHERE RNUM=1 
0

和公正的品種,這裏是另一種方式來做到這一點:

with mins as (
    select id, min(aorb) as min_aorb 
    from mytable 
    ) 
select t.* 
from mytable t 
    inner join mins on mins.id=t.id and mins.min_aorb=t.aorb; 

這避免必須直接將「A」和「B」編碼到查詢中。

0
select id, min(aorb) as min_aorb, 
     min(content) keep (dense_rank first order by aorb) as content 
from ... 
group by id 

將給你一個答案的數據(與大多數其他解決方案相比,節省了大量的I/O)。

0

我投票贊成vkp的回答,因爲只要AORB是字母,它就更有可能得到你需要的東西。如果不需要,我不會硬編碼條件。我也認爲AORB應該有一個不同的名字。今天,可能的值是A和B,但從經驗來看,我可以告訴你有人最終會添加C,D,E或9。然後你必須回去重新編碼UNION/EXISTS邏輯,因爲會出現額外的內容。只要AORB保持您需要的整理順序,ROW_NUMBER()方法就可以工作。我還會告誡,如果數據庫整理更改,它會改變您的結果。

要查看整理效果:

IF OBJECT_ID('tempdb.dbo.#myStuff', 'U') IS NOT NULL 
    DROP TABLE #myStuff ; 

CREATE TABLE #myStuff ( 
    ID int 
    , AORB char(1) /* Watch collation. This is case-sensitive */ collate SQL_Latin1_General_CP1_CS_AS 
    , otherContent varchar(120) 
) ; 
INSERT INTO #myStuff (ID, AORB, otherContent) 
VALUES 
     (1,'a','Lorem ipsum dolor sit amet, consectetur adipiscing elit.') 
    , (1,'A','Nulla malesuada tellus a arcu ultrices suscipit.') 
    , (1,'B','Proin lacinia laoreet pretium.') 
    , (2,'a','Nam commodo, elit sit amet efficitur rutrum, nisi magna semper neque, vitae fermentum nulla erat a felis.') 
    , (3,'A','Vivamus eget augue in felis luctus gravida congue et lectus.') 
    , (3,'B','Phasellus ullamcorper vehicula ornare.') 
    , (4,'A','Vivamus in facilisis nisl.') 
    , (5,'B','Duis accumsan elit nisi, eu sodales metus fermentum ut.') 
    , (6,'D','Aenean ultrices suscipit dui sit amet mollis.') 
    , (6,'C','Maecenas feugiat, ligula et tristique venenatis, lectus lorem ornare dui, id convallis felis sapien non justo.') 
    , (7,'A','Suspendisse vitae mattis leo.') 
    , (7,'9','Nam eu nunc tincidunt, hendrerit elit at, semper diam.') 
    , (7,'a','Quisque ornare erat justo, id venenatis est congue eu. ') 
; 

SELECT t2.id, t2.AORB, t2.otherContent, rn 
FROM (
    SELECT t1.id, t1.AORB, t1.otherContent, ROW_NUMBER() OVER(PARTITION BY t1.ID ORDER BY t1.AORB) AS rn 
    FROM #myStuff t1 
) t2 
WHERE t2.rn=1 
; 

SELECT t2.id, t2.AORB, t2.otherContent, rn 
FROM (
    SELECT t1.id, t1.AORB, t1.otherContent, ROW_NUMBER() OVER(PARTITION BY t1.ID ORDER BY t1.AORB) AS rn 
    FROM #myStuff t1 
) t2 
WHERE t2.rn=1 
; 

這是區分大小寫的拉丁語的排序規則。默認的SQL通常不區分大小寫。