【问题标题】:Nested CASE WHEN statement嵌套 CASE WHEN 语句
【发布时间】:2016-12-10 20:44:18
【问题描述】:

我有一个 CASE WHEN 条件(CompanyGUID 和 LineGUID),我需要使用 4 个不同的列进行 4 个不同的计算。 计算工作正常,但我只是想知道有什么办法让它更方便吗?例如,在这种情况下可能使用 COALESCE 技巧?

CASE WHEN dbo.tblCompanyLocations.CompanyGUID = '29634AF7-D0A2-473D-9574-405C23E10F02' 
      AND dbo.tblQuotes.LineGUID = '1CB72920-B3FC-4822-8030-37B50A2810EB' 
     THEN isnull(ddaWC.archexMod,1) 
     END as ExperienceMod, 

CASE WHEN dbo.tblCompanyLocations.CompanyGUID = '29634AF7-D0A2-473D-9574-405C23E10F02' 
      AND dbo.tblQuotes.LineGUID = '1CB72920-B3FC-4822-8030-37B50A2810EB'           
     THEN case when convert(int,ddawc.premModTtl) <= 0 then 1 
               when convert(int,ddawc.premModTtl) >= 0 
                 then (1 + ddaWC.premschmod / ddawc.premModTtl) end 
     END as ScheduleMod,

CASE WHEN dbo.tblCompanyLocations.CompanyGUID = '29634AF7-D0A2-473D-9574-405C23E10F02' 
      AND dbo.tblQuotes.LineGUID = '1CB72920-B3FC-4822-8030-37B50A2810EB'   
     THEN   isnull(ddaWC.TMpercent,1) END  as  TerritoryMod, 

CASE WHEN dbo.tblCompanyLocations.CompanyGUID = '29634AF7-D0A2-473D-9574-405C23E10F02' 
      AND dbo.tblQuotes.LineGUID = '1CB72920-B3FC-4822-8030-37B50A2810EB' 
     THEN case when convert(int,ddaWC.SchedPercent) = 0 or 
                    ddaWC.SchedPercent is not null 
                 then (isnull(ddaWC.archexMod,1) 
                     * (convert(decimal(5,2),isnull(ddaWC.SchedPercent,1)))) 
                     * isnull(ddaWC.TMpercent,1)
               when ddaWC.SchedPercent is null 
                  then 1 END 
     END as EffectiveMod

【问题讨论】:

  • 更方便是什么意思?不必输入更少的代码?
  • 抱歉,我的意思是我可以使用一次(CompanyGUID 和 LineGUID)并因此有 4 个不同的列吗?
  • 让我们说更好、更专业的查询方式
  • 我在许多生产环境中看到这样的案例陈述,那里没有真正的问题。您可以创建一个映射表并对其进行内部连接(一个表比代码修改更容易维护,让您可以将正在进行的更改转移给可以在表中输入一行而不是修改 sql 代码的人)跨度>
  • 你可以去掉一些不必要的逻辑语句,比如在同一个case语句中同时使用&gt;= 0&lt;=0。这可以用一个比较和一个其他来代替......

标签: sql sql-server tsql reporting-services sql-server-2012


【解决方案1】:

这样的? OUTER APPLY 将执行基于行的选择,如果您的条件未满足,则返回 NULLs。否则它将返回您指定的相同值。仅当您确实需要所有列都使用相同的逻辑时,这才有效。

SELECT otherColumn
      ,ConditionalColumns.*
FROM YourTable
OUTER APPLY
(
    SELECT isnull(ddaWC.archexMod,1) as ExperienceMod, 
           case when convert(int,ddawc.premModTtl) <= 0 then 1 
                when convert(int,ddawc.premModTtl) >= 0 
                then (1 + ddaWC.premschmod / ddawc.premModTtl) end as ScheduleMod,
           isnull(ddaWC.TMpercent,1)  as  TerritoryMod, 
           case when convert(int,ddaWC.SchedPercent) = 0 or ddaWC.SchedPercent is not null 
                then (isnull(ddaWC.archexMod,1) 
                         * (convert(decimal(5,2),isnull(ddaWC.SchedPercent,1)))) 
                         * isnull(ddaWC.TMpercent,1)
                when ddaWC.SchedPercent is null 
                then 1 END as EffectiveMod
    WHERE dbo.tblCompanyLocations.CompanyGUID = '29634AF7-D0A2-473D-9574-405C23E10F02' 
          AND dbo.tblQuotes.LineGUID = '1CB72920-B3FC-4822-8030-37B50A2810EB' 
) AS ConditionalColumns

【讨论】:

  • 针对子查询的外部应用!惊人的。不知道你能做到。
  • @CharlesBretana 是的,太好了!我经常将其用于计算值以避免重复代码。它允许例如类似于 where 中的别名。
【解决方案2】:

像这样:

代码之前的某处:

Declare @compGuid char(37) = '29634AF7-D0A2-473D-9574-405C23E10F02' 
Declare @lineGuid char(37) = '1CB72920-B3FC-4822-8030-37B50A2810EB' 

并修改 SQL 语句中的 From 子句以定义别名
cltblCompanyLocations
qtblQuotes
那么 SQL 代码的 Select 子句中的 case 可以简化为:

 case when cl.CompanyGUID = @compGuid 
          and q.LineGUID = @lineGuid  
      then isnull(ddaWC.archexMod,1) end ExperienceMod, 

 case when cl.CompanyGUID = @compGuid 
          and q.LineGUID = @lineGuid          
      then case when cast(ddawc.premModTtl as int) > 0
                then (1 + ddaWC.premschmod / ddawc.premModTtl)
                else 1 end end ScheduleMod,

 case when cl.CompanyGUID = @compGuid 
         and q.LineGUID = @lineGuid
      then isnull(ddaWC.TMpercent,1) end TerritoryMod, 

 case when cl.CompanyGUID = @compGuid 
         and q.LineGUID = @lineGuid
      then case when cast(ddaWC.SchedPercent as int) = 0 
                   then isnull(ddaWC.archexMod,1) 
                       * cast(ddaWC.SchedPercent as decimal(5,2)))
                       * isnull(ddaWC.TMpercent,1)
                when ddaWC.SchedPercent is null 
                   then 1 end end EffectiveMod

这更具可读性...(请检查逻辑)

【讨论】:

  • 您完成了繁重的工作并清理了逻辑。从我这边+1...我认为,最好的办法是把你和我的结合起来:-)
  • @Shnugo,(这次把 sp 弄对了!)谢谢!我学到了一些东西......我不知道你可以对子查询运行外部应用。以为它只适用于 UDF。
猜你喜欢
  • 2014-07-12
  • 2018-03-20
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-03-12
相关资源
最近更新 更多