是否可以通过一个查询获得两组数据

时间:2012-12-25 10:58:06

标签: sql-server sql-server-2008 tsql stored-procedures

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

现在我有两个存储过程GetAllItemsGetTopThreeeCommentsByItemId

在应用程序中我得到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

4 个答案:

答案 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