具有交叉应用语法的先前记录
Posted
技术标签:
【中文标题】具有交叉应用语法的先前记录【英文标题】:Previous Record With Cross Apply Syntax 【发布时间】:2019-07-24 15:46:40 【问题描述】:我有一个名为 ArchiveActivityDetails
的表格,其中显示了客户维修订单的历史记录。 1 个维修订单将进行多次访问 (ActivityID
),并根据计划访问的可用人员分配一名技术员。
系统会自动分配作业所需的时间,但有时作业需要更长的时间,因此我们手动修改作业。
我从客户那里得到的初步查询是提取手动修改的作业(即:PlannedDuration >=60 分钟的作业)并显示链接到该手动修改的作业的技术人员。
此报告运行良好。
我最近从客户那里得到的请求是现在添加一个列,显示谁是之前的技术人员,该列与维修订单相关联。
我的同事建议我做一个Cross Apply
回到ArchiveActivityDetails
表,然后显示“以前的技术”,但我之前没有使用过Cross Apply
,我在语法上苦苦挣扎,无法得到我的结果想。在我的Cross Apply
中,我使用LAG
来计算“PrevTech”,但是当将其拉入我的主要报告时,我得到NULL
。所以我假设我没有正确执行Cross Apply
。
DECLARE @DateFrom as DATE = '2019-05-20'
DECLARE @DATETO AS DATE = '2019-07-23'
----------------------------------------------------------------------------------
SELECT
AAD.Date
,ASM.ASM
,A.ASM as PrevASM
,ASM.KDGID2
,R.ResourceName
,R.ID_ResourceID
,A.ServiceOrderNumber
,CONCAT(EN.TECHVORNAME, ' ' , EN.TECHNACHNAME) as TechName
,A.PrevTech
,EN.TechnicianID
,AAD.ID_ActivityID
,SO.ServiceOrderNumber
,AAD.VisitNumber
,AAD.PlannedDuration
,AAD.ActualDuration
,AAD.PlannedDuration-AAD.ActualDuration as DIFF
,DR.Original_Duration
FROM
[Easy].[ASMTrans] AS ASM
INNER JOIN
[FS_OTBE].[EngPayrollNumbers] AS EN
ON ASM.KDGID2 = EN.KDGID2
INNER JOIN
[OFSA].[ResourceID] AS R
ON EN.TechnicianID = Try_cast(R.ResourceName as int)
INNER JOIN
[OFSDA].[ArchiveActivityDetails] as [AAD]
ON R.[ID_ResourceID] = AAD.ID_ResourceID
INNER JOIN
[OFSA].[ServiceOrderNumber] SO
ON SO.ID_ServiceOrderNumber = AAD.ID_ServiceOrderNumber
LEFT JOIN
[OFSE].[DurationRevision] DR
on DR.ID_ActivityID = AAD.ID_ActivityID
CROSS APPLY
(
SELECT
AD.Date
,AD.ID_CountryCode
,AD.ID_Status
,Activity_TypeID
,AD.ID_ActivityID
,AD.ID_ResourceID
,SO.ServiceOrderNumber
,ASM.ASM
,LAG(EN.TECHVORNAME+ ' '+EN.TECHNACHNAME) OVER (ORDER BY SO.ServiceOrderNumber,AD.ID_ActivityID) as PrevTech
,AD.VisitNumber
,AD.ID_ServiceOrderNumber
,AD.PlannedDuration
,AD.ActualDuration
,ROW_NUMBER() OVER (PARTITION BY AD.ID_ServiceOrderNumber Order by AD.ID_ActivityID,AD.Date) as ROWNUM
FROM
[Easy].[ASMTrans] AS ASM
INNER JOIN
[FS_OTBE].[EngPayrollNumbers] AS EN
ON ASM.KDGID2 = EN.KDGID2
INNER JOIN
[OFSA].[ResourceID] AS R
ON EN.TechnicianID = Try_cast(R.ResourceName as int)
INNER JOIN
[OFSDA].[ArchiveActivityDetails] as [AD]
ON R.[ID_ResourceID] = AD.ID_ResourceID
INNER JOIN
[OFSA].[ServiceOrderNumber] SO
ON SO.ID_ServiceOrderNumber = AD.ID_ServiceOrderNumber
WHERE
AAD.ID_ActivityID = AD.ID_ActivityID
AND
AD.ID_CountryCode = AAD.ID_CountryCode
AND AD.ID_Status = AAD.ID_Status
AND AD.ID_ResourceID = AAD.ID_ResourceID
AND AD.Activity_TypeID = AAD.Activity_TypeID
AND AD.ID_ServiceOrderNumber = AAD.ID_ServiceOrderNumber
AND AD.Date >= '2019-05-01'
) as A
WHERE
ASM.KDGID2
IN (50008323,50008326,50008329,50008332,50008335,50008338,50008341,50008344,50008347,50008350,50008353,50008356,50008359,50008362,50008365)
AND AAD.ID_Status = 1
AND AAD.ID_CountryCode = 7
AND AAD.Activity_TypeID=91
AND
(
AAD.[Date] BETWEEN IIF(@DateFrom < '20190520','20190520',@DateFrom) AND IIF(@DateTo < '20190520','20190520',@DateTo))
AND AAD.ActualDuration > 11
AND
(
(DR.Original_Duration >= 60)
OR
(DR.ID_ActivityID IS NULL AND AAD.PlannedDuration >= 60))
我希望看到以前的技术经理和以前的区域销售经理来处理手动修改的工作。
业务原因:经理想要查看最初请求手动修改工作的人。请求的时间被高估了,这是在浪费时间。为了更好地计划,他们需要查看谁要求在工作中获得额外的时间,并尝试减少时间。
我将附上ArchiveActivityDetail
表,其中显示了维修订单的历史记录以及预期结果。
【问题讨论】:
【参考方案1】:您在交叉应用中的查询结果将在您的查询中显示为一个表,因此您可以使用top(1)
并按降序排列以获得您想要的第一行排序(它看起来像 ActivityId?也许是 VisitNumber?) .
简化问题的根源,假设您只有一张带有ServiceOrderNumber
、ID_Activity
、ASM
和TECH
的表。要获取活动 2414073 的前一行,您可以这样做:
select top(1) ASM, TECH
from OFSDA.ArchiveActivityDetails as AD
where ID_ServiceOrderNumber = 2370634229 -- same ServiceOrderNumber
and ID_Activity < 2414073 -- previous activities
order by ID_Activity desc -- highest activity less than 2414073
您可能想要使用outer apply
,而不是cross apply
。这是相同的,但您将在第一个活动的主查询中获得一行,它只会在您的应用中包含空值。如果您想从结果中省略第一行,因为它没有前一行,请继续使用交叉应用。
您可以将上述查询放入outer apply()
的括号中并添加别名(Previous
)。在主查询中链接到当前行的值,使用top(1)
仅获取第一行,并按 ID_Activity 降序排列以获取 ID_Activity 最高的行。
select ASM, TECH,
PreviousASM, PreviousTECH
from OFSDA.ArchiveActivityDetails as AD
outer apply (
select top(1) ADInner.ASM as PreviousASM, ADInner.TECH as PreviousTECH
from OFSDA.ArchiveActivityDetails as ADInner
where ADInner.ID_ServiceOrderNumber = AD.ID_ServiceOrderNumber
and ADInner.ID_Activity < AD.ID_Activity
order by ADInnerID_Activity desc
) Previous
where ID_ServiceOrderNumber = 2370634229
【讨论】:
嗨@Jason,我在查询中尝试了外部应用,效果很好。非常感谢。我现在只是尝试优化查询以稍微加快它的速度。这还不错,但看看我能做些什么来让它稍微快一点。任何提示都会很棒。以上是关于具有交叉应用语法的先前记录的主要内容,如果未能解决你的问题,请参考以下文章