从 SQL Server 中 4 列的表中获取每组的前 N ​​行

Posted

技术标签:

【中文标题】从 SQL Server 中 4 列的表中获取每组的前 N ​​行【英文标题】:Get Top N row from each set from table with 4 column in SQL Server 【发布时间】:2017-12-18 10:39:36 【问题描述】:

假设我有一个有 4 列的表:

Col1   Col2   Col3   Col4  

我的初始查询是:

SELECT Col1, Col2, Col3, Col4  
FROM myTable  
ORDER BY Col1, Col2, Col3 DESC, Col4 

我想要的结果是所有 4 列,但是在这种情况下,当 Col1、Col2 相等时,Top N Col3 不同的行。

N=2 的示例:

表格样本数据:

Col1 Col2 Col3  Col4  
---------------------
1    a    2000  s  
1    a    2002  c  
1    a    2001  b  
2    b    1998  s  
2    b    2002  c  
2    b    2000  b  
3    c    2000  b  
1    f    1998  n  
1    g    1999  e

想要的结果:

1    a    2002  c  
1    a    2001  b  
1    f    1998  n  
1    g    1999  e  
2    b    2002  c  
2    b    2000  b  
3    c    2000  b

另外一种描述,当(col1, col2)在多条记录中重复出现时,按照Col3降序排列,只导出这些记录的前N行。

我可以用 SQL 脚本做到这一点,而不用硬编码吗?

【问题讨论】:

对列使用 group by 子句,然后使用 order by col3 desc 得到我们想要的输出 4 个,而不是字段。 group by in SQL in my question不适合,因为字段有不同的值,当按列分组时,每个值都属于自己的组,无法访问前 N Col3! @jarlh:谢谢 【参考方案1】:
declare @t table (Col1 int, Col2 char, Col3 int,  Col4 char);

insert into @t values  
(1,    'a',    2000,  's'),  
(1,    'a',    2002,  'c'),  
(1,    'a',    2001,  'b'),  
(2,    'b',    1998,  's'),  
(2,    'b',    2002,  'c'),  
(2,    'b',    2000,  'b'),  
(3,    'c',    2000,  'b'),  
(1,    'f',    1998,  'n'),  
(1,    'g',    1999,  'e');


declare @N int = 2; -- number per "top"

with cte as
(
select *,
       row_number() over(partition by col1, col2 order by col3 desc) as rn
from @t
)

select *
from cte c
where rn <= @N;

【讨论】:

感谢您提供详细且经过测试的答案,这个答案非常好【参考方案2】:

我认为下面的代码符合预期

declare @tab table (Col1 int, Col2 char(1), Col3 int, Col4 char(1))
declare @N int
insert into @tab
select 1,    'a'   , 2000,  's' 
union all
select 1 ,   'a'  ,  2002 , 'c'  
union all
select 1 ,   'a'  ,  2001 , 'b'  
union all
select 2 ,   'b'  ,  1998 , 's'  
union all
select 2 ,   'b'  ,  2002  ,'c'  
union all
select 2 ,   'b'  ,  2000  ,'b'  
union all
select 3 ,   'c'  ,  2000  ,'b'  
union all
select 1 ,   'f'  ,  1998  ,'n'  
union all
select 1 ,   'g'  ,  1999  ,'e'

;with tab as
(
select ROW_NUMBER() over(partition by t.col1,t.col2 order by t.col3 desc) as row,t.* 
from @tab t
)

select Col1,Col2,Col3,Col4 
from tab
where row < 3

输出

Col1    Col2    Col3    Col4
1        a      2002    c
1        a      2001    b
1        f      1998    n
1        g      1999    e
2        b      2002    c
2        b      2000    b
3        c      2000    b

【讨论】:

谢谢,但 Max 返回 Top Col3 值但我希望在示例中描述的 Col3 订购时有 N 组记录 谢谢,但条件是:当在具有 (Col1,Col2) Equal 的多个记录中,只需导出此记录的 Top N 记录,即按 Col3 降序排序,对不起,很清楚,或者我必须描述更多?【参考方案3】:

方法 1- 适用于 MSSQL

http://sqlfiddle.com/#!6/4bda39/6

with a as (
    select ROW_NUMBER() over(partition by t.col1,t.col2 order by t.col3 desc) as row,t.* 
    from myTable as t) 
select * from a where a.row <= 2

替换 a.row (2 用你的 N)

方法 2- FOR MYSQL

http://sqlfiddle.com/#!9/79e81a/63

SELECT   myTable.Col1, myTable.Col2, myTable.Col3, myTable.Col4
FROM ( 
    Select Col1 as Col1, Col2 as Col2, count(Col1) as cc, AVG(Col3) as aa 
    From myTable 
    group by Col1, Col2) as tt
join  myTable on myTable.Col1 = tt.Col1 and myTable.Col2 = tt.Col2
where myTable.Col3 >= tt.aa
Order by Col1 ,Col2 ,Col3 Desc,Col4 

方法 3- FOR MYSQL

http://sqlfiddle.com/#!9/79e81a/79

SELECT * FROM (
    SELECT CASE Col1
        WHEN @Col1 THEN
            CASE Col2 
                WHEN @Col2 THEN @curRow := @curRow + 1 
                ELSE @curRow := 1
            END
        ELSE @curRow :=1
    END AS rank,
    @Col1 := Col1 AS Col1,
    @Col2 := Col2 AS Col2, 
    Col3, Col4
    FROM myTable p
    JOIN (SELECT @curRow := 0, @Col1 := 0, @Col2 := '') r
    ORDER BY Col1, Col2, Col3 DESC) as tt 
WHERE tt.rank <= 2

替换 tt.rank 将 2 替换为您想要的索引

【讨论】:

请注意问题,当 (Col1 , Col2 ) 在多行重复时,我想要的结果是 Top N Record that order by Col3 现在做了一些小改动

以上是关于从 SQL Server 中 4 列的表中获取每组的前 N ​​行的主要内容,如果未能解决你的问题,请参考以下文章

sql server 查询 order by 与 union 并替换多个列的空值

如何从 SQL Server 中特定数据库的表中获取所有列名?

如何从 SQL Server 中的表中获取不匹配的数据

如何从 SQL Server 中的表中获取行的索引?

如何从 SQL Server 2014 中的 Select 查询中将数据分配给用户定义的表类型

如何使用 SSMA(用于访问 SQL Server)将具有不同列的表迁移到现有表中?