【问题标题】:SQL subquery based on row values with unrelated table基于不相关表的行值的 SQL 子查询
【发布时间】:2015-11-23 11:28:02
【问题描述】:

我需要根据带有一些中等复杂连接的查询中的行值来获取不相关表中的记录计数。所有数据都位于单个 SQL 2012 数据库中的一台服务器上,位于多个不同的表中。

我正在根据审计记录一次重新创建一张工单的工单移动历史记录,并且需要计算由连接创建的行中的跨度的工作日。门票在区域之间移动(分配),并且有关于在任何一个区域应该多长时间的指南。门票可能会多次前往同一区域,每次重新开始计时。

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

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

下面的查询具有带变量和交叉连接的工作解决方案,但它仅适用于硬编码日期,如果我尝试使用它不起作用的字段值,因为它们不是子查询的一部分,并且不能被束缚。

-- DV_im_Audit_ASSIGNMENT.Time 和 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

结果

仅供参考 - 我正在通过 BIRT 4.2 运行此 SQL,我相信很少有 SQL 项不会通过 BIRT

【问题讨论】:

  • 只是为了确定:因为在数据样本中 Detail.RESOLVED_TIME 似乎是事件的解决日期(而不是每次重新分配的日期),它不应该类似于“DV_im_Audit_ASSIGNMENT.Time 之间”和重新分配时间'?在这种情况下,一个选项是通过过滤 Assign_time 和 Reassign_time(没有子查询)与 UPMCCALENDARM1 进行标准连接,然后在所有输出字段上应用“分组依据”以计算“非总线”计数。但是我认为最简单和最有效的方法是存储过程,如果它适用于您的上下文。
  • @Dominique 正确,这将是指标之一,有几个。我正在研究 Resolved time 指标,因为它有一些更长的跨度,当你有逻辑错误时,更长的跨度会导致更明显的错误。
  • @Dominique 谢谢。

标签: sql join sql-server-2012 birt


【解决方案1】:

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

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')。不过问题就这么解决了。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多