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')。不过这样问题就解决了。
我需要根据具有一些中等复杂联接的查询中的行值,计算不相关 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')。不过这样问题就解决了。