4

我需要从数据库中获取一些项目,每个项目的前三个评论。

现在我有两个存储过程GetAllItemsGetTopThreeeCommentsByItemId.

在应用程序中我得到 100 个项目,然后在 foreach 循环中我调用GetTopThreeeCommentsByItemId程序来获得前三个评论。

我知道从性能的角度来看这很糟糕。

是否有一些技术可以通过一个查询来获得这个?

我可以OUTER APPLY用来获得一个顶级评论(如果有的话),但我不知道如何获得三个。

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

我想获取的样本数据

  • 项目_1
    -- 评论_1
    --评论_2 -- 评论
    _3

  • 项目_2——评论_4——
    评论
    _5

4

4 回答 4

1

如果您使用的是 SQL Server 2005 及更高版本(您在这方面不够具体),则一种方法是使用 CTE(通用表表达式)。

使用此 CTE,您可以按某些标准(即您的)对数据进行分区,ItemId并让 SQL 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

在这里,我为每个“分区”(即每个项目)选择最多三个条目(即评论) - 由CommentId.

这是否接近你正在寻找的东西?

于 2012-12-25T11:14:07.477 回答
0

这得到二哥使用 OUTER APPLY:

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

marc 的答案更好,如果您需要向主实体查询“近”实体(例如地理空间、哥哥、最接近到期​​日等),只需使用 OUTER APPLY 即可。

外部应用演练:http ://www.ienablemuch.com/2012/04/outer-apply-walkthrough.html

不过,您可能需要 DENSE_RANK 而不是 ROW_NUMBER/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 回答