Warning: file_get_contents(/data/phpspider/zhask/data//catemap/1/oracle/9.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Sql 每组最大n,同时返回内容_Sql_Oracle_Group By_Greatest N Per Group - Fatal编程技术网

Sql 每组最大n,同时返回内容

Sql 每组最大n,同时返回内容,sql,oracle,group-by,greatest-n-per-group,Sql,Oracle,Group By,Greatest N Per Group,我已经看过其他答案,但在将答案应用于我的申请时遇到了问题。我有一个返回如下内容的查询: SELECT * FROM MYTABLE T; __________________________________________________________ | ID | AORB | ....OTHER (UNIQUE) CONTENT..... | |---------------------------------------------------------|

我已经看过其他答案,但在将答案应用于我的申请时遇到了问题。我有一个返回如下内容的查询:

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
。有时存在计数为1的“唯一”ID,
AORB
可以是
a
B

为了让数据结构更清晰,您可以通过在“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,则返回带有
A
AORB
的行。如果给定id只有一行,则返回该行,而不考虑
AORB

我尝试将a和b查询合并,但由于内容不同,它仍然返回“重复”ID:


我想这就是你想要的:

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”。

您可以使用
行号
顺序对条件进行优先级排序

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

为了多样性,这里有另一种方法:

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”编码到查询中

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

将通过数据一次给出答案(与大多数其他解决方案相比节省了大量I/O)。

我投票支持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通常不区分大小写

这真的很棒,这正是我需要的。我用
替换了
MYTABLE
,因为我的实际查询要复杂得多。
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
;