【问题标题】:Reusing Case Statement for many Columns in same SELECT statement在同一个 SELECT 语句中为多个列重用 Case 语句
【发布时间】:2022-11-11 17:52:21
【问题描述】:

我有一张来自调查的大表,其中所有答案都相似,但我需要使它们保持一致。我需要为所有列重用相同的 case 语句,但这会导致查询非常丑陋且冗长。有没有办法将案例变成存储过程、UDF 或我可以更改被调用列的东西?

例子:

-- Example Case statement I need for all Columns
    CASE 
            WHEN Happy IN ('Yes','True','Y','1') THEN 'Yes'
            WHEN Happy IN ('No','False','N','0') THEN 'No'
            WHEN Happy LIKE 'Don_t Know' or Happy IN ('Unknown','U','999','-1') THEN 'Unknown'
            WHEN Happy IN ('Missing','Blank','-4') THEN 'Missing'
    END AS HappyClean

-- Example table
SELECT Happy
      ,Sad
      ,DownBad
      ,FeelinGood
From Emotions

列的实际数量超过 50,而 Case 实际上长了 2 行,因此您可以看到如果我必须为每一列复制粘贴该代码,代码会多长时间。我正在使用 SQL Server 顺便说一句。

感谢任何帮助!

【问题讨论】:

  • 您当然可以将其封装在一个函数中并将该列作为参数传递。
  • 那是CASE表达,而不是陈述。至于问题,虽然你可以创建一个函数(可能是一个在 2019+ 年可内联的标量函数),这样的方法在 SQL 中不能很好地扩展。 T-SQL 中的划分逻辑通常会阻碍效率,而不是提高效率。经常重复逻辑实际上更高效。
  • 也许,你真的应该有一个名为Feeling 的列,然后是另一个列用于true/false/etc。那么你只需要 1 个CASE 表达式,而不是 50 个。当你需要多次重复一个表达式时,这样的要求通常表明存在设计缺陷。
  • 您可以一次性支付价格以某种方式修复您的数据,方法是保持一致,然后在所有查询中使用“固定”数据。或者,您可以为每个查询付出代价。你选。

标签: sql sql-server case user-defined-functions


【解决方案1】:

您可以只创建一个映射表,将所有替换对插入一次,然后加入:

CREATE TABLE #Mapping
(
  Candidate varchar(255),
  Replacement varchar(255)
);

INSERT #Mapping(Candidate, Replacement)
VALUES('Yes','Yes'),('True','Yes'),('Y','Yes'),('1','Yes'),
  ('No','No'),('False','No'),('N','No'),('0','No'),
  ('Don_t Know','Unknown'),('Unknown','Unknown'),
  ('U','Unknown'),('999','Unknown'),('-1','Unknown'),
  ('Missing','Missing'),('Blank','Missing'),('-4','Missing');

UPDATE e SET Happy = m.Replacement
  FROM dbo.Emotions AS e
  INNER JOIN #Mapping AS m
  ON e.Happy LIKE m.Candidate;

【讨论】:

  • 打我一拳(虽然我加了primary key到候选人)?
  • 很好奇,JOIN 上的 LIKE 做了什么而 = 没有?我以前从未见过这样的做法。
  • @HardCode LIKE 处理来自问题 (WHEN Happy LIKE 'Don_t Know') 的 Don_t Know 的情况 - _ 是通配符,我认为他们可以有直撇号 ' 或智能撇号
  • 为什么不使用左连接,那么未知值可以保留为nullcoalesced 为未知。否则,如果e.Happy LIKE m.Candidate找不到匹配项,您将丢失该行。
  • @Kendle我宁愿不猜测OP想要对他们未包含在问题中的边缘案例值做什么。对于内部连接,上面未提及的任何值都将被单独保留。
【解决方案2】:

您还可以使用虚拟VALUES

SELECT
  HappyClean = m.Replacement
FROM dbo.Emotions AS e
INNER JOIN (VALUES
  ('Yes','Yes'),('True','Yes'),('Y','Yes'),('1','Yes'),
  ('No','No'),('False','No'),('N','No'),('0','No'),
  ('Don_t Know','Unknown'),('Unknown','Unknown'),
  ('U','Unknown'),('999','Unknown'),('-1','Unknown'),
  ('Missing','Missing'),('Blank','Missing'),('-4','Missing')
) AS m(Candidate, Replacement) ON e.Happy LIKE m.Candidate;

【讨论】:

    【解决方案3】:

    对于那些仍然不匹配的答案,我可能会创建一个映射表并在查询中使用左连接链接到它。

    CREATE TABLE MAPPING (a nvarchar(100), b nvarchar(100))
    
    INSERT INTO MAPPING
    VALUES  ('Yes','Yes'),('True','Yes'),('Y','Yes'),('1','Yes'),
            ('No','No'),('False','No'),('N','No'),('0','No'),
            ('Don_t Know','Unknown'),('Unknown','Unknown'),
            ('U','Unknown'),('999','Unknown'),('-1','Unknown'),
            ('Missing','Missing'),('Blank','Missing'),('-4','Missing');
    
    SELECT Happy
          ,m1.b as HappyResult
          ,Sad
          ,m2.b as SadResult
          ,DownBad
          ,m3.b as DownbadResult
          ,FeelinGood
          ,m4.b as FeelinGoodResult
    From Emotions e
    left join MAPPING m1 on m1.a = e.Happy
    left join MAPPING m2 on m2.a = e.Sad
    left join MAPPING m3 on m3.a = e.DownBad
    left join MAPPING m4 on m4.a = e.FeelinGood
    

    【讨论】:

      【解决方案4】:

      我喜欢APPLY (or standard SQL LATERAL in other RDBMS) for this purpose。在我看来,它胜过 CTE 或派生表,因为您可以避免考虑嵌套含义,只需为表达式分配别名,而无需修改查询的其余部分:

      SELECT
        Happy = ...,
        Sad = ...,
        DownBad = ...,
        FeelinGood = ...,
      FROM
        Emotions
        CROSS APPLY (
          SELECT CASE .. END AS HappyClean
        )
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2019-05-06
        • 2023-04-07
        • 1970-01-01
        • 1970-01-01
        • 2016-06-21
        • 2012-12-12
        • 2014-12-05
        相关资源
        最近更新 更多