SELECT与多个子查询到同一个表

Jon*_*ock 13 sql t-sql sql-server subquery

我一遍又一遍地使用相同的SQL模式,我知道必须有更好的方法,但我无法将它拼凑在一起.这是模式的一个简单版本,我将撤回学生的信息和他们签出的最后一本书(如果存在的话):

SELECT TStudents.*,
       BookName = (SELECT TOP 1 BookName 
                     FROM TBookCheckouts 
                    WHERE StudentID = TStudents.ID 
                 ORDER BY DateCheckedOut DESC),
       BookAuthor = (SELECT TOP 1 BookAuthor 
                       FROM TBookCheckouts 
                      WHERE StudentID = TStudents.ID 
                   ORDER BY DateCheckedOut DESC),
       BookCheckout = (SELECT TOP 1 DateCheckedOut 
                         FROM TBookCheckouts 
                         WHERE StudentID = TStudents.ID 
                     ORDER BY DateCheckedOut DESC)
   FROM TStudents
Run Code Online (Sandbox Code Playgroud)

(为了这个例子,请忽略TBookCheckouts应该分成TCheckouts和TBooks的事实)

我想说明的是:我倾向于为同一个表中的列提供大量子查询.我也倾向于需要按日期对这些子查询表进行排序以获得最新记录,因此对于LEFT JOIN来说,这并不是那么简单(至少对我而言).但是请注意,除了返回哪个字段之外,我基本上做了3次相同的子查询.SQL Server可能足够聪明以优化它,但我不这么认为(我肯定需要在阅读执行计划方面做得更好......).

虽然以这种方式构造它可能是有利的(如果我有大量的子查询和子表,有时这最终会更具可读性),但这似乎并不是特别有效.

我已经考虑从派生表执行LEFT JOIN,可能包含ROW_NUMBER()和PARTITION BY,但我似乎无法将它们拼凑在一起.

Tho*_*mas 12

如果您使用的是SQL Server 2005及更高版本,则可以使用如下排名函数:

With LastCheckout As
    (
    Select StudentId, BookName, BookAuthor, DateCheckedOut 
        , Row_Number() Over ( Partition By StudentId Order By DateCheckedOut Desc) As CheckoutRank
    From TBookCheckouts
    )
Select ..., LastCheckout.BookName, LastCheckout.BookAuthor, LastCheckout.DateCheckedOut
From TStudents
    Left Join LastCheckout 
        On LastCheckout.StudentId = TStudents.StudentId
                And LastCheckout.CheckoutRank = 1
Run Code Online (Sandbox Code Playgroud)


A-K*_*A-K 9

在2005年及以后,OUTER APPLY是你的朋友:

SELECT TStudents.*,
       t.BookName ,
       t.BookAuthor ,
       t.BookCheckout
   FROM TStudents
  OUTER APPLY(SELECT TOP 1 s.* 
                     FROM TBookCheckouts AS s
                    WHERE s.StudentID = TStudents.ID 
                 ORDER BY s.DateCheckedOut DESC) AS t
Run Code Online (Sandbox Code Playgroud)