如何在case语句中有超过100个条目作为变量

kil*_*nen 11 t-sql sql-server-2012

我写了一个有 > 100 个选项的 case 语句,在一个简单的查询中,我在 4 个地方使用了相同的语句。

相同的查询两次,它们之间有一个联合,但也在进行计数,因此 group by 也包含 case 语句。

这是为了重新标记某些公司名称,其中同一公司的不同记录拼写不同。

我试图将一个变量声明为 VarChar(MAX)

declare @CaseForAccountConsolidation varchar(max)

SET @CaseForAccountConsolidation = 'CASE 
       WHEN ac.accountName like ''AIR NEW Z%'' THEN ''AIR NEW ZEALAND''
       WHEN ac.accountName LIKE ''AIR BP%'' THEN ''AIR BP''
       WHEN ac.accountName LIKE ''ADDICTION ADVICE%'' THEN ''ADDICTION ADVICE''
       WHEN ac.accountName LIKE ''AIA%'' THEN ''AIA''
       ...
Run Code Online (Sandbox Code Playgroud)

当我在我的 select 语句中使用它时 - 查询只是将 case 语句作为文本返回并且没有对其进行评估。

我也无法在组中使用它 - 我收到以下错误消息:

Each GROUP BY expression must contain at least one column that is not an outer reference.
Run Code Online (Sandbox Code Playgroud)

理想情况下,我希望将 CASE 放在一个地方 - 这样我就没有机会更新一行而不是在其他地方复制它。

有没有办法做到这一点?

我对其他方式持开放态度(比如可能是一个功能 - 但我不确定如何像这样使用它们)

这是我目前使用的 SELECT 示例

SELECT 
   SUM(c.charge_amount) AS GSTExcl
   ,dl.FirstDateOfMonth AS MonthBilled
   ,dl.FirstDateOfWeek AS WeekBilled
   ,CASE 
       WHEN ac.accountName like 'AIR NEW Z%' THEN 'AIR NEW ZEALAND'
       WHEN ac.accountName LIKE 'AIR BP%' THEN 'AIR BP'
       WHEN ac.accountName LIKE 'ADDICTION ADVICE%' THEN 'ADDICTION ADVICE'
       WHEN ac.accountName LIKE 'AIA%' THEN 'AIA'
       ELSE ac.accountName
   END AS accountName
   ,dl.FinancialYear
   ,CONVERT(Date,c.date_charged) AS date_charged
FROM [accession] a
   LEFT JOIN account_code ac ON a.account_code_id = ac.account_code_id
   LEFT Join charge c ON a.accession_id = c.accession_id
   LEFT JOIN dateLookup dl ON convert(date,c.date_charged) = dl.date
WHERE a.datecreated = CONVERT(DATE,now())
GROUP BY
   dl.FirstDateOfMonth
   ,dl.FinancialYear
   ,dl.FirstDateOfWeek
   ,CONVERT(Date,c.date_charged)
   ,CASE 
       WHEN ac.accountName like 'AIR NEW Z%' THEN 'AIR NEW ZEALAND'
       WHEN ac.accountName LIKE 'AIR BP%' THEN 'AIR BP'
       WHEN ac.accountName LIKE 'ADDICTION ADVICE%' THEN 'ADDICTION ADVICE'
       WHEN ac.accountName LIKE 'AIA%' THEN 'AIA'
       ELSE ac.accountName
   END

UNION

SELECT 
   SUM(c.charge_amount) AS GSTExcl
   ,dl.FirstDateOfMonth AS MonthBilled
   ,dl.FirstDateOfWeek AS WeekBilled
   ,CASE 
       WHEN ac.accountName like 'AIR NEW Z%' THEN 'AIR NEW ZEALAND'
       WHEN ac.accountName LIKE 'AIR BP%' THEN 'AIR BP'
       WHEN ac.accountName LIKE 'ADDICTION ADVICE%' THEN 'ADDICTION ADVICE'
       WHEN ac.accountName LIKE 'AIA%' THEN 'AIA'
       ELSE ac.accountName
   END AS accountName
   ,dl.FinancialYear
   ,CONVERT(Date,c.date_charged) AS date_charged
FROM [accession] a
   LEFT JOIN account_code ac ON a.account_code_id = ac.account_code_id
   LEFT Join charge c ON a.accession_id = c.accession_id
   LEFT JOIN dateLookup dl ON convert(date,c.date_charged) = dl.date
WHERE a.datecreated = DATEADD(YEAR,-1,CONVERT(DATE,now()))
GROUP BY
   dl.FirstDateOfMonth
   ,dl.FinancialYear
   ,dl.FirstDateOfWeek
   ,CONVERT(Date,c.date_charged)
   ,CASE 
       WHEN ac.accountName like 'AIR NEW Z%' THEN 'AIR NEW ZEALAND'
       WHEN ac.accountName LIKE 'AIR BP%' THEN 'AIR BP'
       WHEN ac.accountName LIKE 'ADDICTION ADVICE%' THEN 'ADDICTION ADVICE'
       WHEN ac.accountName LIKE 'AIA%' THEN 'AIA'
       ELSE ac.accountName
   END
Run Code Online (Sandbox Code Playgroud)

此 UNION 的目的是返回某个时间段的所有数据,并且还返回之前 12 个月同一时间段的数据

编辑:添加了一个缺失的“CATCH-ALL”
EDIT2:添加了 UNION 语句的第二个 ½
EDIT3:更正了 GROUP BY 以包括一些其他必要的元素

Loz*_*ace 22

将数据放入表格中

CREATE TABLE AccountTranslate (wrong VARCHAR(50), translated(VARCHAR(50));

INSERT INTO AccountTranslate VALUES ('ADDICTION ADVICE%','ADDICTION ADVICE');
INSERT INTO AccountTranslate VALUES ('AIR BP%','AIR BP');
INSERT INTO AccountTranslate VALUES ('AIR NEW Z%', 'AIR NEW ZEALAND');
Run Code Online (Sandbox Code Playgroud)

并加入其中。

SELECT ...,COALESCE(AccountTranslate.translated, ac.accountName) AS accountName
FROM
...., 
account_code ac left outer join 
AccountTranslate at on ac.accountName LIKE AccountTranslate.wrong
Run Code Online (Sandbox Code Playgroud)

这样您就可以避免在多个位置保持数据为最新。只需COALESCE在需要的地方使用即可。您可以VIEW根据其他建议将其合并到 CTE 或s 中。


And*_*y M 11

消除 CASE 表达式重复的一种简单方法是像这样使用 CROSS APPLY:

SELECT 
   SUM(c.charge_amount) AS GSTExcl
   ,dl.FirstDateOfMonth AS MonthBilled
   ,dl.FirstDateOfWeek AS WeekBilled
   ,x.accountName
   ,dl.FinancialYear
   ,CONVERT(Date,c.date_charged) AS date_charged
FROM [accession] a
   LEFT JOIN account_code ac ON a.account_code_id = ac.account_code_id
   CROSS APPLY
   (
    SELECT 
       CASE 
           WHEN ac.accountName like 'AIR NEW Z%' THEN 'AIR NEW ZEALAND'
           WHEN ac.accountName LIKE 'AIR BP%' THEN 'AIR BP'
           WHEN ac.accountName LIKE 'ADDICTION ADVICE%' THEN 'ADDICTION ADVICE'
           WHEN ac.accountName LIKE 'AIA%' THEN 'AIA'
       END AS accountName
   ) AS x
   LEFT Join charge c ON a.accession_id = c.accession_id
   LEFT JOIN dateLookup dl ON convert(date,c.date_charged) = dl.date
GROUP BY
   dl.FirstDateOfMonth
   ,x.AccountName
Run Code Online (Sandbox Code Playgroud)

在 CROSS APPLY 的帮助下,您可以为 CASE 表达式指定一个名称,以便可以在语句中的任何位置引用它。它之所以有效,是因为严格来说,您是在嵌套的SELECT中定义计算列- CROSS APPLY 之后的无 FROM SELECT。

这与引用派生表的别名列相同 - 从技术上讲,这个嵌套的 SELECT 就是。它既是相关子查询又是派生表。作为相关子查询,允许引用外部作用域的列,作为派生表,它允许外部作用域引用它定义的列。

对于使用相同 CASE 表达式的 UNION 查询,您必须在每个分支中定义它,除了使用完全不同的替换方法而不是 CASE 之外,没有其他解决方法。但是,在您的特定情况下,可以在没有 UNION 的情况下获取结果。

两条腿仅在 WHERE 条件上有所不同。一个是这样的:

WHERE a.datecreated = CONVERT(DATE,now())
Run Code Online (Sandbox Code Playgroud)

另一个是:

WHERE a.datecreated = DATEADD(YEAR,-1,CONVERT(DATE,now()))
Run Code Online (Sandbox Code Playgroud)

你可以像这样组合它们:

WHERE a.datecreated IN (
                        CONVERT(DATE,now()),
                        DATEADD(YEAR,-1,CONVERT(DATE,now()))
                       )
Run Code Online (Sandbox Code Playgroud)

并将其应用于此答案开头的修改后的 SELECT 。