我想在一个查询中返回每个部分的前 10 条记录。任何人都可以帮助如何做到这一点?节是表中的列之一。
数据库是 SQL Server 2005。我想按输入的日期返回前 10 名。部分是业务、本地和功能。对于某个特定日期,我只想要前 (10) 个业务行(最近的条目)、前 (10) 个本地行和前 (10) 个特征。
我想在一个查询中返回每个部分的前 10 条记录。任何人都可以帮助如何做到这一点?节是表中的列之一。
数据库是 SQL Server 2005。我想按输入的日期返回前 10 名。部分是业务、本地和功能。对于某个特定日期,我只想要前 (10) 个业务行(最近的条目)、前 (10) 个本地行和前 (10) 个特征。
如果您使用的是 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
如果您的 RankCriteria 有联系,那么您可能会返回 10 多行,而 Matt 的解决方案可能更适合您。
在 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
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
这适用于 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
我这样做:
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;
更新: 此 GROUP BY 示例仅适用于 MySQL 和 SQLite,因为这些数据库比有关 GROUP BY 的标准 SQL 更宽松。大多数 SQL 实现要求选择列表中不属于聚合表达式的所有列也在 GROUP BY 中。
如果我们使用 SQL Server >= 2005,那么我们可以只用一个选择来解决任务:
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;
如果您知道这些部分是什么,您可以执行以下操作:
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
我知道这个帖子有点老了,但我刚刚遇到了一个类似的问题(从每个类别中选择最新的文章),这是我想出的解决方案:
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
这与 Darrel 的解决方案非常相似,但克服了可能返回比预期更多行的 RANK 问题。
尝试了以下方法,它也适用于领带。
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
如果要生成按部分分组的输出,则仅显示每个部分的前n条记录,如下所示:
SECTION SUBSECTION
deer American Elk/Wapiti
deer Chinese Water Deer
dog Cocker Spaniel
dog German Shephard
horse Appaloosa
horse Morgan
...那么以下内容应该适用于所有 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;
建立:
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';
Q) Finding TOP X records from each group(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
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
6 rows selected.
UNION运算符可以为您工作吗?每个部分有一个 SELECT,然后将它们联合在一起。猜猜它只适用于固定数量的部分。
虽然问题是关于 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
此查询涉及 2 个表。OP 的查询仅涉及 1 个表,在这种情况下,基于窗口函数的解决方案可能更有效。
You can try this approach. This query returns 10 most populated cities for each country.
SELECT city, country, population
FROM
(SELECT city, country, population,
@country_rank := IF(@current_country = country, @country_rank + 1, 1) AS country_rank,
@current_country := country
FROM cities
ORDER BY country, population DESC
) ranked
WHERE country_rank <= 10;