4

データベースから項目ごとに上位 3 つのコメントを取得する必要があります。

これで、2 つのストアド プロシージャGetAllItemsGetTopThreeeCommentsByItemId.

アプリケーションで 100 個のアイテムを取得し、foreach ループでプロシージャを呼び出しGetTopThreeeCommentsByItemIdて上位 3 つのコメントを取得します。

これがパフォーマンスの観点から悪いことはわかっています。

1回のクエリでこれを取得できるテクニックはありますか?

OUTER APPLYトップ コメントを 1 つ (もしあれば) 取得するために使用できますが、3 つ取得する方法がわかりません。

Items {ItemId, Title, Description, Price etc.}
Comments {CommentId, ItemId etc.}

取得したいサンプルデータ

  • アイテム_1
    --コメント_1
    --コメント_2 -- コメント
    _3

  • アイテム_2
    --コメント_4
    --コメント_5

4

4 に答える 4

1

SQL Server 2005以降を使用している場合、1つのアプローチはCTE(共通テーブル式)を使用することです(その点で十分に具体的ではありません)。

この CTE を使用すると、データをいくつかの基準 (つまり、独自の基準) でパーティション分割し、ItemIdSQL Server ですべての行に番号を付けて、これらの「パーティション」ごとに 1 から開始し、いくつかの基準で並べ替えることができます。

だから、次のようなことを試してください:

;WITH ItemsAndComments AS
(
   SELECT 
       i.ItemId, i.Title, i.Description, i.Price,
       c.CommentId, c.CommentText,
       ROW_NUMBER() OVER(PARTITION BY i.ItemId ORDER BY c.CommentId) AS 'RowNum'
   FROM 
       dbo.Items i
   LEFT OUTER JOIN 
       dbo.Comments c ON c.ItemId = i.ItemId
   WHERE
      ......
)
SELECT 
   ItemId, Title, Description, Price,
   CommentId, CommentText
FROM 
   ItemsAndComments
WHERE
   RowNum <= 3

ここでは、各「パーティション」(つまり各アイテム) に対して最大 3 つのエントリ (つまりコメント) を選択していますCommentId

それはあなたが探しているものに近づきますか??

于 2012-12-25T11:14:07.477 に答える
0

これは、OUTER APPLY を使用して 2 つの兄を取得します。

select m.*, elder.*
from Member m
outer apply
(
 select top 2 ElderBirthDate = x.BirthDate, ElderFirstname = x.Firstname
 from Member x 
 where x.BirthDate < m.BirthDate 
 order by x.BirthDate desc
) as elder
order by m.BirthDate, elder.ElderBirthDate desc

ソースデータ:

create table Member
(
 Firstname varchar(20) not null, 
 Lastname varchar(20) not null,
 BirthDate date not null unique
);

insert into Member(Firstname,Lastname,Birthdate) values
('John','Lennon','Oct 9, 1940'),
('Paul','McCartney','June 8, 1942'),
('George','Harrison','February 25, 1943'),
('Ringo','Starr','July 7, 1940');

出力:

Firstname            Lastname             BirthDate  ElderBirthDate ElderFirstname
-------------------- -------------------- ---------- -------------- --------------------
Ringo                Starr                1940-07-07 NULL           NULL
John                 Lennon               1940-10-09 1940-07-07     Ringo
Paul                 McCartney            1942-06-08 1940-10-09     John
Paul                 McCartney            1942-06-08 1940-07-07     Ringo
George               Harrison             1943-02-25 1942-06-08     Paul
George               Harrison             1943-02-25 1940-10-09     John

(6 row(s) affected)

ライブ テスト: http://www.sqlfiddle.com/#!3/19a63/2

マークの答えの方が優れています。「近い」エンティティ(地理空間、兄、期日までの最も近い日付など)をメインエンティティに照会する必要がある場合は、 OUTER APPLY を使用してください。

外部適用のチュートリアル: http://www.ienablemuch.com/2012/04/outer-apply-walkthrough.html

ROW_NUMBER/RANK の代わりに DENSE_RANK が必要になる場合があります。これは、コメントがトップであるという基準が引き分けになる可能性があるためです。TOP 1 は 1 つ以上、TOP 3 は 3 つ以上を生成する可能性があります。そのシナリオの例 (DENSE_RANK ウォークスルー): http://www.anicehumble.com/2012/03/postgresql-denserank.html

于 2012-12-25T11:13:03.557 に答える
0

GetAllItems と GetTopThreeeCommentsByItemId を呼び出す単一のストアド プロシージャを記述し、一時テーブルで結果を取得し、それらのテーブルを結合して、必要な単一の結果セットを生成できます。

ストアド プロシージャを使用する機会がない場合でも、データ アクセス層から単一の SQL スクリプトを実行することにより、同じことを行うことができます。これは、GetAllItems および GetTopThreeeCommentsByItemId を呼び出し、結果を一時テーブルに取り込み、後でそれらを結合して単一の結果セットを返します。 .

于 2012-12-25T11:15:49.737 に答える
0

row_numberステートメントを使用してステートメントを選択し、上位3つだけを選択することをお勧めします

select a.* from ( Select *,row_number() over(partition by column)[dup] ) as a where dup<=3

于 2012-12-25T11:57:30.543 に答える