各カテゴリの上位10件のレコードを選択します


208

1つのクエリで各セクションの上位10件のレコードを返したい。誰でもそれを行う方法を手伝ってくれる?セクションは、テーブルの列の1つです。

データベースはSQL Server 2005です。入力した日付で上位10件を返したいのですが。セクションは、ビジネス、ローカル、特集です。特定の日付について、上位(10)のビジネス行(最新のエントリ)、上位(10)のローカル行、および上位(10)の機能のみが必要です。


これらの答えのどれかがうまくいきましたか?
カイルデラニー2017

3
私たちは決して知ることはないと思います...
デニー

12年経ちましたが、それらがうまくいったかどうかはわかりません。
アロマ

回答:


222

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のソリューションの方が適している場合があります。


31
トップ10が本当に必要な場合は、Rank()ではなくRowNumber()に変更します。そのときは関係ありません。
Mike L

3
これは機能しますが、最初のキーがRankCriteriaであるインデックスがない場合、rank()はクエリプランナーによってフルテーブルソートに変換される可能性があることに注意してください。この場合、個別のセクションを選択し、クロス適用して、RankCriteria descで並べられた上位10を選択することで、より良い距離を得ることができます。
Joe Kearney

すばらしい答えです!必要なものをほぼ正確に手に入れました。結局DENSE_RANK、番号付けにギャップがないものに行きました。+1
Michael Stramel 2013年

1
@Facbedこれはテーブルの単なるエイリアスです。
Darrel Miller

15
Sql Serverを使用している人にとって、Mike Lが述べたRowNumber()関数はROW_NUMBER()です。
randomraccoon 2016

99

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

2
:ソリューションについてより説明的にしてください。参照:回答方法
2012年

CTEの選択クエリにwhere句を含めることができますか?
16

1
@tohaはい、できます
KindaTechy 2017年

1
「T-SQLで」と言っても、これはROW_NUMBER関数を実装するすべてのデータベースで機能します。たとえば、SQLiteでこのソリューションを使用しました。
トニー

postgres sqlでも動作します。私は「order by [prioritise_field] desc」を使用しなければならなかった
Phun

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

2
ただし、これはSectionがnullの行では機能しません。「どこ(tt.Sectionがnullでt.Sectionがnull)またはtt.Section = t.Section」と言う必要があります
Matt Hamilton

29
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

エイリアス「m」のテーブルとは何ですか?
チョーキー2016

@Chalkyそれはタイプミスrです。修繕。
lorond 16

魅力のように働いた。ありがとうございました!
Ron Nuni 2017年

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;

更新: GROUP BYのこの例は、MySQLとSQLiteでのみ機能します。これらのデータベースは、GROUP BYに関して標準SQLよりも寛容だからです。ほとんどのSQL実装では、集約式の一部ではない選択リスト内のすべての列もGROUP BYに含まれている必要があります。


1
それは動作しますか?Article_id以外のアーティクルのすべての列について、「a.somecolumnは、select関数リストでは無効です。これは集約関数またはgroup by句に含まれていないためです。」
Blorgbeardが

1
GROUP BYで指定された列に機能的に依存する他の列を含めることができるはずです。機能的に依存していない列があいまいです。しかし、RDBMSの実装によっては、その通りです。MySQLで動作しますが、IIRCはInterBase / Firebirdで失敗します。
ビルカーウィン、

1
これは、セクションの上位11件のレコードがすべて同じ日付である場合に機能しますか?それらはすべて11のカウントを持ち、結果は空のセットになります。
Arth 2015年

いいえ、それらがすべて同じ日付である場合は、何らかの関係を破る必要があります。例については、stackoverflow.com / questions / 121387 /…を参照してください。
Bill Karwin、2015年

1
@carlosgg、記事がセクションと多対多の関係にある場合、記事をセクションにマップするための交差テーブルが必要になります。次に、クエリはm2m関係の交差テーブルに結合し、article_idとsectionでグループ化する必要があります。これで始められるはずですが、ソリューション全体をコメントで書き上げることはしません。
Bill Karwin 2017年

16

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;

1
+1私はこのソリューションが単純であることを気に入っていますが、0または1を返す句top 1caseステートメントを使用してどのように機能するかを説明できますorder byか?
Ceres、2015年

3
TOP 1はここでWITH TIESと連携します。WITH TIESは、ORDER BY = 0の場合、SELECTがこのレコード(TOP 1のため)とORDER BY = 0を持つすべてのレコード(WITH TIESのため)を取ることを意味します
Vadim Loboda

9

セクションが何であるかがわかっている場合は、次のことができます。

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

3
これが最も簡単な方法です。
Hector Sosa Jr

3
あなたは150を持っている場合、またはカテゴリは日によって変動、週などしている場合しかし、これは非効率的だろう
ラファバラガン

1
承知しましたが、OPを引用します:「セクションはビジネス、ローカル、機能です」。3つの静的カテゴリがある場合、これが最適な方法です。
Blorgbeardは2017

9

私はこのスレッドが少し古いことを知っていますが、同様の問題にぶつかっただけです(各カテゴリから最新の記事を選択してください)。これが私が思いついた解決策です。

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問題を克服します。


CTE Sirを使用する理由 メモリ消費を減らしますか?
16

@toha CTEがよりシンプルで理解しやすいため
エンジニア

正解です!! 対応するレコードがないとのレコードはないため、のJOIN代わりにinnerを使用して最適化できます。LEFT JOINTopCategoryArticlesArticle
リバースエンジニア、

6

以下を試してみて、ネクタイでもうまくいきました。

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

5

セクションごとにグループ化された出力を生成する場合は、各セクションの上位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';

各セクションの最初のレコードだけが必要な場合、これは機能しません。複数のレコードを持つすべてのセクショングループを削除します。<= 2を<= 1に置き換えてみました
nils

@nilsセクションの値は、鹿、犬、馬の3つだけです。クエリを<= 1に変更すると、各セクションに1つのサブセクションが表示されます。鹿の場合はAmerican Elk / Wapiti、犬の場合はCocker Spaniel、馬の場合はAppaloosaです。これらは、アルファベット順に各セクションの最初の値でもあります。このクエリは、他のすべての値を削除すること目的としています。
クレイグ

しかし、クエリを実行しようとすると、カウントがすべて> = 1になるため、すべてが削除されます。各セクションの最初のサブセクションは保持されません。<= 1のクエリを実行して、各セクションの最初のサブセクションが表示されるかどうかを教えてください。
nilの

@nilsこんにちは、スクリプトからこの小さなテストデータベースを再作成し、<= 1を使用してクエリを実行しました。各セクションから最初のサブセクション値が返されました。どのデータベースサーバーを使用していますか?選択したデータベースに関連する可能性は常にあります。MySQLでこれを実行したところ、便利で期待どおりに動作したためです。初めてやったときはかなり確信しています(投稿したものが実際にデバッグなしで機能することを確認したかったのですが)、Sybase SQL AnywhereまたはMS SQL Serverのいずれかを使用してやったと確信しています。
Craig

それは私にとってmysqlで完璧に機能しました。私は彼が使用しなかった理由クエリー少しはわからないビットに変更<=サブセクションのvarchar型のフィールドのために..私はそれを変更し、x2.subsection = x1.subsection
Mahen Nakar

4

マイトUNIONのあなたのためのオペレータの仕事は?セクションごとに1つのSELECTを設定し、それらをまとめてUNIONします。ただし、一定数のセクションでしか機能しないと思います。


4

Q)各グループ(Oracle)からTOP Xレコードを検索する

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行を選択しました。



問題はOracleではなくSQL Serverに関するものでした。
クレイグ

2

質問は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つのテーブルのみが含まれます。この場合、ウィンドウ関数ベースのソリューションの方が効率的です。


1

このアプローチを試すことができます。このクエリは、各国で最も人口の多い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;

このソリューションは、9つの同じ母集団を持つ1つの国のレコードを持つテーブルがある場合、テストケースに合格しません。たとえば、9つの使用可能なレコードすべてを順番に返すのではなく、nullを返します。この問題を修正するための提案はありますか?
Mojgan Mazouchi 2018
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.