如何用case语句连接和汇总随机逗号分隔值?

时间:2018-04-29 11:55:12

标签: sql sum concatenation case

我有一个视图,这是一个简单的案例陈述。

SELECT CAST(
         CASE 
              WHEN [value] = 'Canadian' and fieldid = 78
                 THEN 5
              WHEN [value] = 'US' and fieldid = 78
                 Then 3
              WHEN [value] = 'UK' and fieldid = 78
                 Then 1
              When [value] = 'Australia' and fieldid = 78
                 Then 1
              When [value] = 'Israel' and fieldid = 78
                 Then 1 
              When [value] = 'Others' and fieldid = 78
                 Then 1

到目前为止,当列具有匹配值时,一切都可以正常,但是有时列可以保存由逗号分隔的随机多个值。我怎么能算出来? 这就是现在发生的事情。

 +----+------------------+--------+
 | ID | Value            | Points |
 +----+------------------+--------+
 |  1 | Canadian         |   5    |
 |  2 | UK               |   1    |
 |  3 | Canadian,UK      |   0    |
 +----+----------+----------------+

预期结果

 +----+------------------+--------+
 | ID | Value            | Points |
 +----+------------------+--------+
 |  1 | Canadian         |   5    |
 |  2 | UK               |   1    |
 |  3 | Canadian,UK      |   6    |
 +----+----------+----------------+

2 个答案:

答案 0 :(得分:2)

从SQL Server 2017开始,您可以使用:

SELECT DISTINCT t.ID, t.[value],
         SUM(CASE 
              WHEN s.[value] = 'Canadian' and fieldid = 78
                 THEN 5
              WHEN s.[value] = 'US' and fieldid = 78
                 Then 3
              WHEN s.[value] = 'UK' and fieldid = 78
                 Then 1
              When s.[value] = 'Australia' and fieldid = 78
                 Then 1
              When s.[value] = 'Israel' and fieldid = 78
                 Then 1 
              When s.[value] = 'Others' and fieldid = 78
                 Then 1
           END) OVER(PARTITION BY ID) AS Points
FROM tab t
CROSS APPLY STRING_SPLIT(t.[value], ',') s
ORDER BY t.id;

<强> DBFiddle Demo

在单列中存储多个值会违反第一范式,应该避免使用。

可以简化为:

SELECT DISTINCT t.ID, t.[value],
             SUM(CASE 
                  WHEN s.[value] = 'Canadian' and fieldid = 78
                     THEN 5
                  WHEN s.[value] = 'US' and fieldid = 78
                     Then 3
                  WHEN s.[value] IN ('UK', 'Australia' , 'Israel', 'Others') 
                       and fieldid = 78
                     Then 1
               END) OVER(PARTITION BY ID) AS Points
FROM tab t
CROSS APPLY STRING_SPLIT(t.[value], ',') s
ORDER BY t.id;

答案 1 :(得分:2)

您只需使用CASELIKE

即可
SELECT ((CASE WHEN ',' + [value] + ',' LIKE '%,Canadian,%' and fieldid = 78
             THEN 5 ELSE 0
         END) +
        (CASE WHEN ',' + [value] + ',' LIKE '%,US,%' and fieldid = 78
             THEN 3 ELSE 0
         END) +
        (CASE WHEN ',' + [value] + ',' LIKE '%,UK,%' and fieldid = 78
             THEN 1 ELSE 0
         END) +
        (CASE WHEN ',' + [value] + ',' LIKE '%,Australia,%' and fieldid = 78
             THEN 1 ELSE 0
         END) +
        (CASE WHEN ',' + [value] + ',' LIKE '%,Israel,%' and fieldid = 78
             THEN 1 ELSE 0
         END) +
        (CASE WHEN ',' + [value] + ',' LIKE '%,Others,%' and fieldid = 78
             THEN 1 ELSE 0
         END)
       ) as val

尽管如此,强烈地强烈反对强烈建议您不要在单个列中存储多个值。 SQL旨在在列中存储单个值(至少对于标量列类型,字符串是标量类型)。

您应该有一个单独的表,它是一个联结/关联表,每个实体和国家/地区都有一行。

编辑:如果您使用的是SQL Server 2017或者有分割字符串功能,我会建议您这样做:

SELECT t.ID, t.[value], COALESCE(s.points, 0) as points
FROM tab t OUTER APPLY
     (SELECT SUM(CASE WHEN s.[value] = 'Canadian' THEN 5
                      WHEN s.[value] = 'US' THEN 3
                      WHEN s.[value] IN ('UK', 'Australia' , 'Israel', 'Others') THEN 1
                 END) AS Points
      FROM STRING_SPLIT(t.[value], ',') s
      WHERE t.fieldid = 78
     ) s
ORDER BY t.id;