我需要从数据库中获取一些项目,每个项目都有前三个评论。
现在我有两个存储过程GetAllItems
和GetTopThreeeCommentsByItemId
。
在应用程序中我得到100个项目然后在foreach循环中我调用GetTopThreeeCommentsByItemId
过程来获得前三个评论。
我知道从性能的角度来看,这是不好的。
是否有一些技术允许通过一个查询获得此功能?
我可以使用OUTER APPLY
获得一条最高评论(,如果有的话),但我不知道如何获得三条评论。
Items {ItemId, Title, Description, Price etc.}
Comments {CommentId, ItemId etc.}
我想要的示例数据
ITEM_1
- comment_1
- 评论_2
- comment_3
ITEM_2
- comment_4
- comment_5
答案 0 :(得分:1)
如果你使用的是SQL Server 2005及更新版本(在这方面你不够具体),一种方法是使用CTE(公用表表达式)。
使用此CTE,您可以按照某些条件对数据进行分区 - 即ItemId
- 并为每个“分区”提供从1开始的所有行的SQL Server编号,按某些条件排序。
所以尝试这样的事情:
;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
排序。
这会接近你想要的吗?
答案 1 :(得分: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's answer更好,如果您需要向主要实体查询“近”实体(例如地理空间,兄弟,最近日期到期日等),请使用外部申请。
外部申请演练:http://www.ienablemuch.com/2012/04/outer-apply-walkthrough.html
您可能需要DENSE_RANK而不是ROW_NUMBER / RANK,因为评论的标准可能会产生关联。 TOP 1可以产生不止一个,TOP 3也可以产生超过三个。该场景的示例(DENSE_RANK演练):http://www.anicehumble.com/2012/03/postgresql-denserank.html
答案 2 :(得分:0)
您可以编写一个调用GetAllItems和GetTopThreeeCommentsByItemId的存储过程,在临时表中获取结果并连接这些表以生成所需的单个结果集。
如果您没有机会使用存储过程,您仍然可以通过从数据访问层运行单个SQL脚本来执行相同操作,该脚本调用GetAllItems和GetTopThreeeCommentsByItemId并将结果导入临时表并稍后将它们连接以返回单个结果集。
答案 3 :(得分:0)
使用row_number语句选择语句并单独选择前3个
会更好从中选择。* ( 选择*,row_number()over(按列分区)[dup] ) 作为一个 其中dup&lt; = 3