【问题标题】:How to Sum Numbers after Piped Values如何在管道值之后对数字求和
【发布时间】:2015-09-10 20:45:08
【问题描述】:

我在 SQL 中有一个列,其中包含用管道分隔的值。在每个值之后,都有一个我想汇总的数字,但我不知道最好的方法。

列如下所示:

{Carrots:1}|{Bananas:2}|{Watermelon:1}

我正在做类似的事情:

SELECT 
    NOME, PRICE,
    SUM(CASE WHEN VEGETABLE LIKE '%Carrots%' THEN 1 ELSE 0 END) as Carrots,
    SUM(CASE WHEN VEGETABLE LIKE '%Banana%'  THEN 1 ELSE 0 END) as Banana,
    SUM(CASE WHEN VEGETABLE LIKE '%Watermelon%' THEN 1 ELSE 0 END) as Watermelon
FROM 
    Market
GROUP BY 
    NOME, PRICE

但这种方式只会增加一次价值,

column1 的输出为:1 Carrot , 1 Banana, 1 Watermelon;

但我想添加例如 2(在 : 之后,它是数字 2)。

会是这样吗:1 Carrot, 2 Banana, 1 Watermelon.

【问题讨论】:

  • 这里的正确做法是修复有缺陷的数据库设计。关系数据库中的一列不应包含多个离散值。当然,您会尝试找到变通方法,但最终如果您更正设计,您的情况会好得多。
  • jpw,是的,我知道,但我们无法更改数据库... :(

标签: sql split sum substring


【解决方案1】:

这会起作用,虽然我同意 jpw 的回复,但我很“高兴”地处理这样的数据,这些数据是由不会改变其格式的客户发送的。

SELECT
Name, Price,
CAST(SUM(CASE WHEN [Vegetable] LIKE '%Carrots%' THEN SUBSTRING([Vegetable],CHARINDEX('Carrots:',[Vegetable])+8,1) ELSE 0 END) AS VARCHAR) + ' Carrot , ' +
CAST(SUM(CASE WHEN [Vegetable] LIKE '%Banana%'  THEN SUBSTRING([Vegetable],CHARINDEX('Bananas:',[Vegetable])+8,1) ELSE 0 END) AS VARCHAR) + ' Banana , ' +
CAST(SUM(CASE WHEN [Vegetable] LIKE '%Watermellon%' THEN SUBSTRING([Vegetable],CHARINDEX('Watermellon:',[Vegetable])+12,1) ELSE 0 END) AS VARCHAR) + ' Watermellon' as Column1 
FROM Market
GROUP BY name, price

输出

1 Carrot , 2 Banana , 1 Watermellon

【讨论】:

    【解决方案2】:

    请找到以下可以满足您的目的的代码。您可以将此代码转换为 2 个函数。一个将字符串转换为数字字符串,然后另一个将每个数字相加

    Declare @String varchar(4000) = '{Carrots:1}|{Bananas:2}|{Watermellon:1}';            
    Declare @NumOnly varchar(100) = '%[^0-9]%';
    Declare @Sum int = 0;
    Declare @Cnt int = 1;
    
    --Convert String to a numeric String
    WHILE PatIndex(@NumOnly, @String) > 0
    BEGIN
        SET @String = Stuff(@String, PatIndex(@NumOnly, @String), 1, '');
    END   
    SELECT @String;
    
    --add up each character (digit) in the numeric string
    WHILE @Cnt <= LEN(@String)
    BEGIN
        SET @Sum = @Sum + CONVERT(INT, SUBSTRING(@String,@Cnt,1));
        SET @Cnt = @Cnt + 1;
    END     
    SELECT @Sum;
    

    【讨论】:

      【解决方案3】:

      您可以使用SUBSTRING() 函数来实现此目的,不过最好按照 cmets 中的建议更改模型。但是,这并不总是可能的,因此如果您必须使用这种格式,您可以使用以下内容:

      SELECT 
          NOME, 
          PRICE,
          SUM(CASE WHEN VEGETABLE  LIKE '%Carrots%' THEN SUBSTRING(VEGETABLE , CHARINDEX(':', VEGETABLE , CHARINDEX('Carrots', VEGETABLE ))+1, 1) ELSE 0 END) as Carrots,
          SUM(CASE WHEN VEGETABLE  LIKE '%Banana%'  THEN SUBSTRING(VEGETABLE , CHARINDEX(':', VEGETABLE , CHARINDEX('Banana', VEGETABLE ))+1, 1) ELSE 0 END) as Banana,
          SUM(CASE WHEN VEGETABLE  LIKE '%Watermelon%' THEN SUBSTRING(VEGETABLE , CHARINDEX(':', VEGETABLE , CHARINDEX('Watermelon', VEGETABLE ))+1, 1) ELSE 0 END) as Watermelon
      FROM 
          Market
      GROUP BY 
          NOME, PRICE
      

      编辑:作为为什么这种模型是一个坏主意的完美论据,我上面的解决方案没有考虑多位数字。我提出了一个解决方案(如下),可以弥补这一点,但我将原始代码作为案例研究,以说明为什么字符串操作不好玩。

      DECLARE @VEGETABLE VARCHAR(100) = '{Carrots:1000}|{Bananas:20}|{Watermelon:1}'
      
      SELECT 
          SUM(CASE 
              WHEN @VEGETABLE  LIKE '%Carrots%' 
              THEN SUBSTRING(
                  @VEGETABLE , 
                  CHARINDEX(':', @VEGETABLE , CHARINDEX('Carrots', @VEGETABLE ))+1, 
                  CHARINDEX('}', @VEGETABLE , CHARINDEX('Carrots', @VEGETABLE )) - (CHARINDEX(':', @VEGETABLE , CHARINDEX('Carrots', @VEGETABLE ))+1)) 
              ELSE 0 END) as Carrots,
          SUM(CASE 
              WHEN @VEGETABLE  LIKE '%Banana%' 
              THEN SUBSTRING(
                  @VEGETABLE , 
                  CHARINDEX(':', @VEGETABLE , CHARINDEX('Banana', @VEGETABLE ))+1, 
                  CHARINDEX('}', @VEGETABLE , CHARINDEX('Banana', @VEGETABLE )) - (CHARINDEX(':', @VEGETABLE , CHARINDEX('Banana', @VEGETABLE ))+1)) 
              ELSE 0 END) as Bananas,
          SUM(CASE 
              WHEN @VEGETABLE  LIKE '%Watermelon%' 
              THEN SUBSTRING(
                  @VEGETABLE , 
                  CHARINDEX(':', @VEGETABLE , CHARINDEX('Watermelon', @VEGETABLE ))+1, 
                  CHARINDEX('}', @VEGETABLE , CHARINDEX('Watermelon', @VEGETABLE )) - (CHARINDEX(':', @VEGETABLE , CHARINDEX('Watermelon', @VEGETABLE ))+1)) 
              ELSE 0 END) as Carrots
      

      【讨论】:

      • 效果很好,非常感谢! (幸运的是,不会有多位数;))
      • 我很乐意提供帮助!如果此答案或任何答案解决了您的问题,请单击复选标记考虑accepting it。这向更广泛的社区表明您找到了解决方案,并为回答者和您自己赢得了一些声誉。
      猜你喜欢
      • 2013-04-27
      • 2022-11-21
      • 2012-10-25
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2019-02-15
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多