1 つのクエリで各セクションから上位 10 件のレコードを返したいと考えています。誰でもそれを行う方法を手伝ってもらえますか? セクションは、テーブル内の列の 1 つです。
データベースは SQL Server 2005 です。入力した日付の上位 10 件を返したいと考えています。セクションは、ビジネス、ローカル、および機能です。ある特定の日付について、上位 (10) のビジネス行 (最新のエントリ)、上位 (10) のローカル行、および上位 (10) の機能のみが必要です。
1 つのクエリで各セクションから上位 10 件のレコードを返したいと考えています。誰でもそれを行う方法を手伝ってもらえますか? セクションは、テーブル内の列の 1 つです。
データベースは 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 を使用する場合、1 つの選択のみでタスクを解決できます。
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 問題を克服しています。
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
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 行が選択されました。
UNION演算子は役に立ちますか? セクションごとに 1 つの SELECT を用意してから、それらを一緒に UNION します。ただし、固定数のセクションでのみ機能すると思います。
このアプローチを試すことができます。このクエリは、国ごとに最も人口の多い 10 都市を返します。
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;