按语法分区

Partition by syntax

我有以下语句可用于获取特定 DDI 的最新数据行。我现在想要做的是用一长串 DDI 替换 where 语句中的单个 DDI,但每个 DDI 仍然只有最新的一行。我很确定我需要使用 OVER 和 PARTITION BY 为每个 DDI 获得一个单独的 window 但即使阅读微软文档和更简化的教程我仍然无法获得正确的语法。我怀疑我只需要朝着正确的方向轻推。谁能帮忙?

https://docs.microsoft.com/en-us/sql/t-sql/queries/select-over-clause-transact-sql?view=sql-server-2017

http://www.sqltutorial.org/sql-window-functions/sql-partition-by/

SELECT TOP 1
       [Start Time]
      ,[Agent Name]
      ,[Reference]
      ,[charged op. (sec)]
      ,[Type]         
      ,[Activation ID] as [actid]          
  FROM [iPR].[dbo].[InboundCallsView]    
  Where [type] = 'Normal operator call'    
  AND [DDI] = @DDI    
  Order By [Start Time] Desc

不确定您计划如何处理 DDI 的多个值,但这可能是个问题。最好的方法是使用 table 值参数。如果你传入一个分隔列表,你也必须拆分字符串,这不是处理此类事情的好方法。

此查询将 return 每个 DDI 的最新查询。

SELECT 
    [Start Time]
    , [Agent Name]
    , [Reference]
    , [charged op. (sec)]
    , [Type]
    , [actid]
from
(
    SELECT 
        [Start Time]
        , [Agent Name]
        , [Reference]
        , [charged op. (sec)]
        , [Type]
        , [actid]
        , RowNum = ROW_NUMBER() over(partition by DDI order by [Start Time] desc)
      FROM [iPR].[dbo].[InboundCallsView]

      where [type] = 'Normal operator call'
        --and [DDI] = @DDI
) x
where x.RowNum = 1

所以让我们假设 table 包含此数据(请注意我如何清理列名以删除空格、特殊字符等):

+---+------------------+--------+------+----+------+---+
| 1 | 2019-03-28 08:00 | agent1 | foo1 | 60 | foo1 | 1 |
+---+------------------+--------+------+----+------+---+
| 1 | 2019-03-28 09:00 | agent2 | foo2 | 70 | foo2 | 2 |
| 2 | 2019-03-27 08:00 | agent3 | foo3 | 80 | foo3 | 3 |
| 2 | 2019-03-27 09:00 | agent4 | foo4 | 90 | foo4 | 4 |
+---+------------------+--------+------+----+------+---+

如您所说,您可以使用window函数来获得您想要的。但是,让我先向您展示一种不需要 window 函数的方法。

您需要 StartTime 是该 DDI 最大值的记录。您可以使用以下查询获取每个 DDI 的最大值 StartTime

SELECT
    ddi, 
    max_start = MAX(StartTime)
FROM InboundCallsView
GROUP BY ddi

然后您可以将该查询加入您的基础 table/view 以获得您想要的记录。使用中级 CTE,您可以执行以下操作:

WITH 
    ddiWithMaxStart AS
    (
        SELECT
            ddi, 
            max_start = MAX(StartTime)
        FROM InboundCallsView
        GROUP BY ddi
    )
SELECT InboundCallsView.*
FROM InboundCallsView
    INNER JOIN ddiWithMaxStart ON
        ddiWithMaxStart.ddi = InboundCallsView.ddi
        AND ddiWithMaxStart.max_start = InboundCallsView.StartTime

现在,如果你真的想使用 WINDOW 功能,你可以使用 ROW_NUMBER 来达到类似的效果:

WITH 
    ddiWithRowNumber AS
    (
        SELECT
            InboundCallsView.*, 
            rn = ROW_NUMBER() OVER
            (
                PARTITION BY ddi
                ORDER BY ddi, StartTime DESC
            )
        FROM InboundCallsView
    )
SELECT *
FROM ddiWithRowNumber
WHERE rn = 1

请注意,使用此方法,您无需将基础 view/table 加入中间 CTE。

您可以测试每种方法的性能,看看哪种方法最适合您。