2017-06-15 41 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通常不区分大小写。