如何在特定日期之后优化查询唯一的第一个数据行?

时间:2015-08-14 07:21:06

标签: sql sql-server

我的表客户端有这样的列:

ClientId    LastChanged
671154  2012-07-21 14:35:40.780
671154  2012-07-21 14:35:41.630
671155  2012-07-21 14:37:24.213

我也有表ClientsHistory,其列如下:

ClientId    Changed                 Name                                    StateCode
671154      2012-07-21 14:35:40.780 91C6672EB2D4496AB34D3C                  22654624
671154      2012-07-21 14:35:41.630 55E345FE6A144B0E92A6026D8B461CEA        22654624
671154      2013-03-13 12:56:33.943 D32841A8EBAB44999C966D2F597DC240        22654624  

我想在LastChanged日期之后在ClientsHistory中查询客户端和仅第一行:

SELECT  (   SELECT  TOP 1
                    Name
            FROM    dbo.ClientsHistory
            WHERE   ClientId    = c.ClientId
            AND     Changed     > c.LastChanged
            ORDER   BY  [Changed]   ASC
        )   ,
        (   SELECT  TOP 1
                    StateCode
            FROM    dbo.СlientsHistory
            WHERE   ClientId    = c.ClientId
            AND     Changed     > c.LastChanged
            ORDER   BY  [Changed]   ASC
        )   ,
        c.ClientId,
        c.LastChanged
FROM    Clients c

如何重写此查询以消除ClientsHistory表中每个字段的子查询?

先谢谢。

3 个答案:

答案 0 :(得分:1)

您可以使用CTE,排名函数ROW_NUMBERLEFT JOIN

WITH Hist AS
(
    SELECT c.ClientId, Changed, Name, StateCode, c.LastChanged,
           RN = ROW_NUMBER() OVER (PARTITION BY c.ClientId
                                   ORDER BY Changed DESC)
    FROM dbo.Clients c INNER JOIN dbo.ClientsHistory ch
         ON c.ClientId = ch.ClientId
    WHERE c.LastChanged > ch.Changed
)
SELECT c.ClientId, c.LastChanged, h.Changed, Name, StateCode
FROM dbo.Clients c LEFT JOIN Hist h
   ON c.ClientId = h.ClientId
   AND c.LastChanged = h.LastChanged  -- necessary since ClientId is not unique in hist
   AND h.RN = 1

Demo

答案 1 :(得分:1)

为了消除每个列的单独子查询的需要,您可以像这样使用APPLY

SELECT ch.Name, 
        ch.StateCode, 
        c.ClientId,
        c.LastChanged
    FROM dbo.Clients c
    OUTER APPLY (SELECT TOP 1 * 
                 FROM  dbo.ClientsHistory
                 WHERE ClientId = c.ClientId 
                    AND Changed > c.LastChanged
                 ORDER BY Changed ASC) ch

此处,将为客户端中的每一行执行子查询。

答案 2 :(得分:0)

此查询必须返回相同的结果。你能测试一下:

SELECT temp.Name,
       temp.StateCode,
       c.ClientId,
       c.LastChanged
FROM Clients c
INNER JOIN 
     (SELECT TOP 1 c2.ClientId 
             c2.Name, 
             c2.StateCode
      FROM Clients c2
      INNER JOIN dbo.ClientsHistory ch
          ON ch.ClientId = c2.ClientId 
          AND ch.Changed > c2.LastChanged
      ORDER   BY  [Changed]   ASC) temp 
  ON temp.ClientId = c.ClientId