SQL 基于不相关行值的子查询 table

SQL subquery based on row values with unrelated table

我需要根据具有一些中等复杂联接的查询中的行值,计算不相关 table 中的记录数。所有数据都在单个 SQL 2012 数据库中的一台服务器上,在几个不同的 table 上。

我正在从审计记录中一次为一张工单重新创建工单移动历史记录,并且需要为连接创建的行中的跨度计算工作日。门票在区域之间移动(ASSIGNMENT),并且有关于在任何一个区域应该多长时间的指导方针。一张票可能会去同一个区域多次,每次都重新开始计时。

我需要在工作日计算中考虑公司假期。在查看了 SE 上工作日计算的几种解决方案后,我决定使用公司日历 table (dbo.UPMCCALENDARM1) 并计算跨度之间的日期。似乎是个好主意...

我不知道如何使用行值作为日期计数查询的参数。

下面的查询有使用变量和交叉连接的有效解决方案,但它只适用于硬编码日期,如果我尝试使用字段值它不起作用,因为它们不是子的一部分查询不能绑定。

-- between DV_im_Audit_ASSIGNMENT.Time and Detail.RESOLVED_TIME

理论上,我可能可以在子查询中使用这个完整查询来获取日期计数,但这是我能做到的最短的时间,并且仍然可以获得干净的数据。对于按需报告来说,这是一个相当沉重的负担,那将是我最后的选择。所以我想联系 UPMCCALENDARM1,因为列出了每次出现的 DV_im_Audit_ASSIGNMENT.Time 和 Detail.RESOLVED_TIME。

可以吗?如果有怎么办?

declare @NonBus integer 
set @NonBus = '0'
set @NonBus = (select Count(UPMCCALENDARM1.DATE) as NonBus
            from dbo.UPMCCALENDARM1
            where UPMC_BUSINESS_DAY = 'f'
            and UPMCCALENDARM1.DATE 
            between '2015-08-01' and '2015-08-31'
--          between DV_im_Audit_ASSIGNMENT.Time and Detail.RESOLVED_TIME
            )

select DV_im_Audit_ASSIGNMENT.Incident_ID
, DV_im_Audit_ASSIGNMENT.Old_ASSIGNMENT
, DV_im_Audit_ASSIGNMENT.New_ASSIGNMENT
, DV_im_Audit_ASSIGNMENT.Time as Assign_Time
, B.Time as Reassign_Time
, Detail.OPEN_TIME
, Cal.NonBus
, NonBus
, Detail.RESOLVED_TIME
, A.rownumA
, B.rownumB

from dbo.DV_im_Audit_ASSIGNMENT

--Get RownumA as a select join so I can work with it here, else get an invalid column name 'rownumA' error
left join(select Incident_ID
        , Old_ASSIGNMENT
        , New_ASSIGNMENT
        , [Time]
        , rownumA = ROW_NUMBER() OVER (ORDER BY  DV_im_Audit_ASSIGNMENT.Incident_ID, DV_im_Audit_ASSIGNMENT.Time)
        from dbo.DV_im_Audit_ASSIGNMENT
        where Incident_ID = ?
        ) as A
            on DV_im_Audit_ASSIGNMENT.Incident_ID = A.Incident_ID
            and DV_im_Audit_ASSIGNMENT.New_ASSIGNMENT = A.New_ASSIGNMENT
            and DV_im_Audit_ASSIGNMENT.Time = A.Time 

--Get time assigned to next group, is problomatic when assigned to the same group multiple times.
left join(select Incident_ID
        , Old_ASSIGNMENT
        , New_ASSIGNMENT
        , [Time]
        , rownumB = ROW_NUMBER() OVER (ORDER BY  DV_im_Audit_ASSIGNMENT.Incident_ID, DV_im_Audit_ASSIGNMENT.Time)
        from dbo.DV_im_Audit_ASSIGNMENT
        where Incident_ID = ?
        ) as B
            on DV_im_Audit_ASSIGNMENT.Incident_ID = B.Incident_ID
            and DV_im_Audit_ASSIGNMENT.New_ASSIGNMENT = B.Old_ASSIGNMENT
            and DV_im_Audit_ASSIGNMENT.Time < B.Time 
        and rownumA = (B.rownumB - 1)  

--Get current ticket info
left join (select Incident_ID
        , OPEN_TIME
        , RESOLVED_TIME
        from dbo.DV_im_PROBSUMMARYM1_Detail
        where Incident_ID = ?
        ) as Detail 
    on DV_im_Audit_ASSIGNMENT.Incident_ID = Detail.Incident_ID


--Count non-bussiness days.  This section is in testing and does not use dataview as a source.
-- this gets the date count for one group of dates, need a different count for each row based on assign time. 
cross join (Select Count(UPMCCALENDARM1.DATE) as NonBus
            from dbo.UPMCCALENDARM1
            where UPMC_BUSINESS_DAY = 'f'
            and UPMCCALENDARM1.DATE 
            between '2015-08-01' and '2015-08-30'
--          between DV_im_Audit_ASSIGNMENT.Time and Detail.RESOLVED_TIME
            ) as Cal


--Get data for one ticket
where DV_im_Audit_ASSIGNMENT.Incident_ID = ?

ORDER BY  DV_im_Audit_ASSIGNMENT.Incident_ID, DV_im_Audit_ASSIGNMENT.Time

结果

仅供参考 - 我 运行 这个 SQL 通过 BIRT 4.2,我相信很少 SQL 项目不会通过 BIRT

根据@Dominique 的建议,我创建了一个自定义标量函数(使用 SSMS 中的向导),我使用了日期的默认值,因为我开始使用存储过程,这使得测试更容易。这个问题需要一个函数,因为它将 return 每行一个值,而存储过程则不会。

SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
-- =============================================
-- Author:      James Jenkins
-- Create date: September 2015
-- Description: Counts Business Days for UPMC during a span of dates
-- =============================================
CREATE FUNCTION dbo.UPMCBusinessDayCount 
(
    -- Add the parameters for the function here
    @StartDate date = '2015-08-01',
    @EndDate date = '2015-08-31'
)
RETURNS int
AS
BEGIN
    -- Declare the return variable here
    DECLARE @BusDay int

    -- Add the T-SQL statements to compute the return value here
    SELECT @BusDay = Count(UPMCCALENDARM1.DATE) 
        from dbo.UPMCCALENDARM1
        where UPMC_BUSINESS_DAY = 't'
        and UPMCCALENDARM1.DATE between @StartDate and @EndDate

    -- Return the result of the function
    RETURN @BusDay

END
GO

在数据库中创建函数后,我将这两行添加到我的 select 语句中,它运行良好。

--Custom function counts business days on UPMCCALENDARM1
, dbo.UPMCBusinessDayCount(DV_im_Audit_ASSIGNMENT.Time, Detail.RESOLVED_TIME) as BusDay

我可以将此函数用于其中包含日期数据的任何跨度(或数据库中的任何查询)。我可能会删除默认日期并添加第三个参数来计算非工作日 (UPMC_BUSINESS_DAY = 'f')。不过这样问题就解决了。