jbc*_*dge 189 sql sql-server sql-server-2005 greatest-n-per-group
我想在一个查询中返回每个部分的前10条记录.任何人都可以帮忙解决这个问题吗?Section是表中的一列.
数据库是SQL Server 2005.我想按输入的日期返回前10名.部分是业务,本地和功能.对于一个特定日期,我只想要前(10)个业务行(最近的条目),前(10)个本地行和前(10)个特征.
Dar*_*ler 201
如果你使用SQL 2005,你可以做这样的事情......
SELECT rs.Field1,rs.Field2
FROM (
SELECT Field1,Field2, Rank()
over (Partition BY Section
ORDER BY RankCriteria DESC ) AS Rank
FROM table
) rs WHERE Rank <= 10
Run Code Online (Sandbox Code Playgroud)
如果您的RankCriteria有关联,那么您可能会返回超过10行,Matt的解决方案可能对您更好.
小智 83
在T-SQL中,我会这样做:
WITH TOPTEN AS (
SELECT *, ROW_NUMBER()
over (
PARTITION BY [group_by_field]
order by [prioritise_field]
) AS RowNo
FROM [table_name]
)
SELECT * FROM TOPTEN WHERE RowNo <= 10
Run Code Online (Sandbox Code Playgroud)
Mat*_*ton 35
这适用于SQL Server 2005(编辑以反映您的澄清):
select *
from Things t
where t.ThingID in (
select top 10 ThingID
from Things tt
where tt.Section = t.Section and tt.ThingDate = @Date
order by tt.DateEntered desc
)
and t.ThingDate = @Date
order by Section, DateEntered desc
Run Code Online (Sandbox Code Playgroud)
lor*_*ond 28
SELECT r.*
FROM
(
SELECT
r.*,
ROW_NUMBER() OVER(PARTITION BY r.[SectionID] ORDER BY r.[DateEntered] DESC) rn
FROM [Records] r
) r
WHERE r.rn <= 10
ORDER BY r.[DateEntered] DESC
Run Code Online (Sandbox Code Playgroud)
Bil*_*win 18
我是这样做的:
SELECT a.* FROM articles AS a
LEFT JOIN articles AS a2
ON a.section = a2.section AND a.article_date <= a2.article_date
GROUP BY a.article_id
HAVING COUNT(*) <= 10;
Run Code Online (Sandbox Code Playgroud)
更新: GROUP BY的这个示例仅适用于MySQL和SQLite,因为这些数据库比关于GROUP BY的标准SQL更宽松.大多数SQL实现要求select-list中不属于聚合表达式的所有列也在GROUP BY中.
Vad*_*oda 11
如果我们使用SQL Server> = 2005,那么我们只能用一个select来解决任务:
declare @t table (
Id int ,
Section int,
Moment date
);
insert into @t values
( 1 , 1 , '2014-01-01'),
( 2 , 1 , '2014-01-02'),
( 3 , 1 , '2014-01-03'),
( 4 , 1 , '2014-01-04'),
( 5 , 1 , '2014-01-05'),
( 6 , 2 , '2014-02-06'),
( 7 , 2 , '2014-02-07'),
( 8 , 2 , '2014-02-08'),
( 9 , 2 , '2014-02-09'),
( 10 , 2 , '2014-02-10'),
( 11 , 3 , '2014-03-11'),
( 12 , 3 , '2014-03-12'),
( 13 , 3 , '2014-03-13'),
( 14 , 3 , '2014-03-14'),
( 15 , 3 , '2014-03-15');
-- TWO earliest records in each Section
select top 1 with ties
Id, Section, Moment
from
@t
order by
case
when row_number() over(partition by Section order by Moment) <= 2
then 0
else 1
end;
-- THREE earliest records in each Section
select top 1 with ties
Id, Section, Moment
from
@t
order by
case
when row_number() over(partition by Section order by Moment) <= 3
then 0
else 1
end;
-- three LATEST records in each Section
select top 1 with ties
Id, Section, Moment
from
@t
order by
case
when row_number() over(partition by Section order by Moment desc) <= 3
then 0
else 1
end;
Run Code Online (Sandbox Code Playgroud)
如果您知道这些部分是什么,您可以:
select top 10 * from table where section=1
union
select top 10 * from table where section=2
union
select top 10 * from table where section=3
Run Code Online (Sandbox Code Playgroud)
我知道这个帖子有点旧,但我刚刚遇到了类似的问题(从每个类别中选择最新的文章),这就是我提出的解决方案:
WITH [TopCategoryArticles] AS (
SELECT
[ArticleID],
ROW_NUMBER() OVER (
PARTITION BY [ArticleCategoryID]
ORDER BY [ArticleDate] DESC
) AS [Order]
FROM [dbo].[Articles]
)
SELECT [Articles].*
FROM
[TopCategoryArticles] LEFT JOIN
[dbo].[Articles] ON
[TopCategoryArticles].[ArticleID] = [Articles].[ArticleID]
WHERE [TopCategoryArticles].[Order] = 1
Run Code Online (Sandbox Code Playgroud)
这与Darrel的解决方案非常相似,但克服了可能返回比预期更多行的RANK问题.
小智 6
Q) 从每个组中查找 TOP X 条记录(Oracle)
SQL> select * from emp e
2 where e.empno in (select d.empno from emp d
3 where d.deptno=e.deptno and rownum<3)
4 order by deptno
5 ;
EMPNO ENAME JOB MGR HIREDATE SAL COMM DEPTNO
Run Code Online (Sandbox Code Playgroud)
7782 CLARK MANAGER 7839 09-JUN-81 2450 10
7839 KING PRESIDENT 17-NOV-81 5000 10
7369 SMITH CLERK 7902 17-DEC-80 800 20
7566 JONES MANAGER 7839 02-APR-81 2975 20
7499 ALLEN SALESMAN 7698 20-FEB-81 1600 300 30
7521 WARD SALESMAN 7698 22-FEB-81 1250 500 30
Run Code Online (Sandbox Code Playgroud)
选择了 6 行。
如果要生成按部分分组的输出,则只显示每个部分的前n条记录,如下所示:
SECTION SUBSECTION
deer American Elk/Wapiti
deer Chinese Water Deer
dog Cocker Spaniel
dog German Shephard
horse Appaloosa
horse Morgan
Run Code Online (Sandbox Code Playgroud)
...那么以下内容应该适用于所有 SQL 数据库。如果您想要前 10 名,只需在查询结束时将 2 更改为 10。
select
x1.section
, x1.subsection
from example x1
where
(
select count(*)
from example x2
where x2.section = x1.section
and x2.subsection <= x1.subsection
) <= 2
order by section, subsection;
Run Code Online (Sandbox Code Playgroud)
建立:
create table example ( id int, section varchar(25), subsection varchar(25) );
insert into example select 0, 'dog', 'Labrador Retriever';
insert into example select 1, 'deer', 'Whitetail';
insert into example select 2, 'horse', 'Morgan';
insert into example select 3, 'horse', 'Tarpan';
insert into example select 4, 'deer', 'Row';
insert into example select 5, 'horse', 'Appaloosa';
insert into example select 6, 'dog', 'German Shephard';
insert into example select 7, 'horse', 'Thoroughbred';
insert into example select 8, 'dog', 'Mutt';
insert into example select 9, 'horse', 'Welara Pony';
insert into example select 10, 'dog', 'Cocker Spaniel';
insert into example select 11, 'deer', 'American Elk/Wapiti';
insert into example select 12, 'horse', 'Shetland Pony';
insert into example select 13, 'deer', 'Chinese Water Deer';
insert into example select 14, 'deer', 'Fallow';
Run Code Online (Sandbox Code Playgroud)
小智 5
尝试了以下内容,它也与关系有效.
SELECT rs.Field1,rs.Field2
FROM (
SELECT Field1,Field2, ROW_NUMBER()
OVER (Partition BY Section
ORDER BY RankCriteria DESC ) AS Rank
FROM table
) rs WHERE Rank <= 10
Run Code Online (Sandbox Code Playgroud)
虽然问题是关于 SQL Server 2005,但大多数人已经继续前进,如果他们确实找到了这个问题,那么在其他情况下,首选答案可能是使用这篇CROSS APPLY
博客文章中所示的答案。
SELECT *
FROM t
CROSS APPLY (
SELECT TOP 10 u.*
FROM u
WHERE u.t_id = t.t_id
ORDER BY u.something DESC
) u
Run Code Online (Sandbox Code Playgroud)
该查询涉及2个表。OP 的查询仅涉及 1 个表,在这种情况下,基于窗口函数的解决方案可能会更有效。