按语法分区
Partition by syntax
我有以下语句可用于获取特定 DDI 的最新数据行。我现在想要做的是用一长串 DDI 替换 where 语句中的单个 DDI,但每个 DDI 仍然只有最新的一行。我很确定我需要使用 OVER 和 PARTITION BY 为每个 DDI 获得一个单独的 window 但即使阅读微软文档和更简化的教程我仍然无法获得正确的语法。我怀疑我只需要朝着正确的方向轻推。谁能帮忙?
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。
您可以测试每种方法的性能,看看哪种方法最适合您。
我有以下语句可用于获取特定 DDI 的最新数据行。我现在想要做的是用一长串 DDI 替换 where 语句中的单个 DDI,但每个 DDI 仍然只有最新的一行。我很确定我需要使用 OVER 和 PARTITION BY 为每个 DDI 获得一个单独的 window 但即使阅读微软文档和更简化的教程我仍然无法获得正确的语法。我怀疑我只需要朝着正确的方向轻推。谁能帮忙?
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。
您可以测试每种方法的性能,看看哪种方法最适合您。