SQL Server 2008:WHERE子句和短路查询中的CASE语句

时间:2014-11-19 18:06:24

标签: sql sql-server-2008 case

我正在尝试在过程工作中进行此查询。

现在它过滤掉状态6和8的保留期之前的数据。还有其他状态。我想确保保留逻辑仅适用于(6,8)中的状态而不适用于其他类型的状态。此过程不会返回其他状态的数据。我可以将查询短路只运行6和8状态并返回6和8以外的状态数据吗?

DECLARE @ReportRetentionPeriod INT = 0
SELECT @ReportRetentionPeriod = [PropertyValue] FROM [CQM].[dbo].[CompanyProperties] WHERE [PropertyName] = 'ReportRetentionPeriod'

SELECT
    DISTINCT
    JD.[Id] AS JobDetailId
    ,JD.[EntityId]
    ,JD.[QueueStatusId] AS QueueStatus
    ,RF.[FileName]
    ,RF.[CreatedOn] AS GeneratedOn  
    ,QS.[Name] AS QueueStatusName
FROM [dbo].[JobDetail] JD
INNER JOIN [dbo].[QueueStatus] AS QS ON QS.[Id] = JD.[QueueStatusId]
LEFT JOIN [dbo].[ReportFile] RF ON RF.[Id] = JD.[FileId]
WHERE JD.JobId = 1234
-- Added codition to use file createdon for completed jobs and job detail createdon for error'd jobs
AND ((GETDATE() - @ReportRetentionPeriod) < CASE QS.[Id]
    WHEN 6 THEN 
        CONVERT(DATETIME, RF.[CREATEDON], 101)
    WHEN 8 THEN
        CONVERT(DATETIME, JD.[CreatedOn], 101)
    END)

使用case语句,因为我必须使用不同的日期来比较不同的状态。

1 个答案:

答案 0 :(得分:1)

几乎每当你在case条款中使用where时,你就走错了路。此外,您需要明确声明如果QS.[Id]不是6或8,则不需要其他标准。如上所述,当QS.[Id]不是6或8时,您的代码会评估(GETDATE() - @ReportRetentionPeriod) < NULL。你的where子句应该是:

WHERE JD.JobId = 1234
AND (( QS.[Id] = 6 and DATEADD(DAY, -1*ReportRetentionPeriod, GETDATE()) 
                       < CONVERT(DATETIME, RF.[CREATEDON], 101))
     OR (QS.[Id] = 8 and DATEADD(DAY, -1*ReportRetentionPeriod, GETDATE()) 
                         < CONVERT(DATETIME, JD.[CreatedOn], 101))
     OR QS.[Id] not in (6,8))

虽然最终会持续一段时间,但它的表现会更好,因为优化程序在解释and / or构造时会有比解释时更多的选项case


如果是我,我可能还会将日期逻辑放在您获得保留期的行中,而不是在评估时:

DECLARE @ReportRetentionDate DATETIME
SELECT @ReportRetentionDate = DATEADD(DAY, -1*[PropertyValue], GETDATE()) 
FROM [CQM].[dbo].[CompanyProperties] 
WHERE [PropertyName] = 'ReportRetentionPeriod'

SELECT
    DISTINCT
    JD.[Id] AS JobDetailId
    ,JD.[EntityId]
    ,JD.[QueueStatusId] AS QueueStatus
    ,RF.[FileName]
    ,RF.[CreatedOn] AS GeneratedOn  
    ,QS.[Name] AS QueueStatusName
FROM [dbo].[JobDetail] JD
INNER JOIN [dbo].[QueueStatus] AS QS ON QS.[Id] = JD.[QueueStatusId]
LEFT JOIN [dbo].[ReportFile] RF ON RF.[Id] = JD.[FileId]
WHERE JD.JobId = 1234
    AND (( QS.[Id] = 6 and @ReportRetentionDate < CONVERT(DATETIME, RF.[CREATEDON], 101))
         OR (QS.[Id] = 8 and @ReportRetentionDate < CONVERT(DATETIME, JD.[CreatedOn], 101))
         OR QS.[Id] not in (6,8))