【问题标题】:SQL Server: how do I SUM column values if the name of the column contains a word?SQL Server:如果列名包含单词,我如何对列值求和?
【发布时间】:2010-06-25 08:36:11
【问题描述】:

在我的 SQL 表中:

Period| Brand A small Bags| Brand A big bags| Brand D Shoes| ...|  Brand X Shoes
2010  |   10              | 20              | 30           | ...| 200           

如何对列名中包含某些单词(例如鞋子)的列求和?

预期结果:

Period | Sum of Bags | Sum of Shoes | ..
2010   | 30          | 230          | ..

【问题讨论】:

  • 你能告诉我们为什么表格是这样的结构吗?
  • 如果一个品牌被重命名,例如“A品牌”更改为“Z品牌”会怎样?如果“Shoes”需要拆分为“Dress Shoes”和“Athletic Shoes”会怎样?
  • 我需要此结构中的数据,以便在另一个应用程序中导入和读取。意识到了这一点的限制。所以我改变了结构,以后会在sql中转置它

标签: sql sql-server sum calculated-columns


【解决方案1】:

您不能没有动态 SQL 并查询 information_schema 表或对其进行硬编码。你能重组你的数据吗,也许像下面这样?

Brands (BrandId, BrandName)
ItemTypes (ItemId, ItemName)
Stock(BrandId, ItemId, Period, Quantity)

编辑

可能还有更多原因,但这里是您当前表结构存在问题的一些原因。

  • 表中的最大列数为 1024,因此您不能一直为每个品牌/商品排列添加列。

  • 如果某个品牌生产包包和鞋子,您将多次重复有关该品牌的信息。每次重复此类信息时,都可能会出现细微的差异和异常情况。此外,如果品牌更改名称,您需要更新该列以及引用该列的所有代码。

  • 如果不对所有排列进行硬编码并记住在添加新品牌时更新该代码,您就无法进行简单的计算,例如对所有行李求和。

  • 您根本无法进行一些查询(或者至少不是没有很大困难) - 例如带回所有提供鞋子的品牌的名称。

【讨论】:

  • @marilyn - 虽然可以使用动态 SQL,但不建议这样做!最好的方法是按照上面的建议重构您的数据,而不是尝试通过解析列名来提取这些数据。
  • “你根本不能做一些查询(或者至少不是没有很大的困难)”——一针见血:如果你能写简单的 SQL DML,比如'sum for shoes in period 2010' 那么你的 SQL DDL 是错误的。
【解决方案2】:

您不能在列名上使用通配符(仅在内容上)。

列数不应改变,因此您可以按照以下方式构建查询:

select period, sum([Brand A small bags]) + sum([Brand A big bags]) as [sum of bags],
   sum([Brand D shoes]) + sum([Brand X shoes]) as [sum of shoes]
from yourtable
group by period

但按照 Martin Smith 的建议,重组数据会更好。

【讨论】:

    【解决方案3】:

    嗯,我想尝试解决这个问题,作为我自己的练习,因为我正在更深入地学习 SQL。我认为给定架构的问题已得到充分记录,我对此不再多说。

    要使此代码正常工作,源数据中的列必须是物理 列(即,不是表变量或视图中的列)。如果有更多的类型不仅仅是包和鞋子,您可以将此代码抽象为函数等等。我只是想把算法的东西记下来。要使其正常工作还有许多其他注意事项,但如前所述,非规范化数据也有全套注意事项。

    所以我们开始吧:

    编辑: 版本 2。感谢 Martin 提供的帮助。这是一个非常巧妙的技巧,尽管它可能很少使用。

    我假设列名将匹配搜索模式(它已经足够硬编码了,所以为什么还要检查)。

    DECLARE @sql nvarchar(max)
    SET @sql = 'SELECT Period, '
    
    
    -- Build column sum for bags
    DECLARE @bagsColumns nvarchar(max)
    
    SELECT
        @bagsColumns = COALESCE(@bagsColumns + '+', N'') + '[' + COLUMN_NAME + ']'
        FROM INFORMATION_SCHEMA.COLUMNS
        WHERE TABLE_NAME = 'SumTest' AND COLUMN_NAME LIKE '%bags%'
    
    SET @sql = @sql + @bagsColumns + ' AS ''Sum of Bags'', '
    
    
    -- Build column sum for shoes
    DECLARE @shoesColumns nvarchar(max)
    
    SELECT
        @shoesColumns = COALESCE(@shoesColumns + '+', N'') + '[' + COLUMN_NAME + ']'
        FROM INFORMATION_SCHEMA.COLUMNS
        WHERE TABLE_NAME = 'SumTest' AND COLUMN_NAME LIKE '%shoes%'
    
    SET @sql = @sql + @shoesColumns + ' AS ''Sum of Shoes'''
    
    
    SET @sql = @sql + ' FROM SumTest'
    
    EXEC(@sql)
    

    【讨论】:

    • 你可以避开光标DECLARE @BagSum nvarchar(max); SELECT @BagSum = COALESCE(@BagSum + '+','SELECT Period,') + '[' + COLUMN_NAME + ']' FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_NAME = 'BagsAndShoes' AND COLUMN_NAME LIKE '%bags%'; IF (@@ROWCOUNT > 0) BEGIN SET @BagSum = @BagSum + ' AS SumOfBags FROM BagsAndShoes' ; EXEC sp_executesql @BagSum END
    • @Martin:非常感谢您的提示!正如我所说,我还在学习。我用第 2 版更新了我的答案。
    • 看起来不错。可以通过INFORMATION_SCHEMA.COLUMNS(如下)的一个查询来做到这一点,但你有它可能会更清楚。
    • DECLARE @Bg nvarchar(max); DECLARE @Sh nvarchar(max); DECLARE @Dyn nvarchar(max); SELECT @Bg = CASE WHEN COLUMN_NAME LIKE '%Bags%' THEN ISNULL(@Bg + '+','') + '[' + COLUMN_NAME + ']' ELSE @Bg END,@Sh = CASE WHEN COLUMN_NAME LIKE '%Shoes%' THEN ISNULL(@Sh + '+','') + '[' + COLUMN_NAME + ']' ELSE @Sh END FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_NAME = 'BagsAndShoes' AND COLUMN_NAME LIKE '%Bags%' OR COLUMN_NAME LIKE '%Shoes%' SET @Dyn = 'SELECT Period' + ISNULL(',' + @Bg + ' AS SumOfBags', '') + ISNULL(',' + @Sh + ' AS SumOfShoes', '') + ' FROM SumTest' EXEC sp_executesql @Dyn
    • @Martin:是的,我认为第二个版本更清晰,更容易抽象成一个函数(表名,列匹配字符串),虽然第三个版本更紧凑。我会在这里澄清一下,因为性能很可能不是问题。
    【解决方案4】:
    SELECT PERIOD, [Brand A small Bags] + [Brand A big bags] [Sum of Bags] ... etc
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2017-12-26
      • 1970-01-01
      • 2021-11-30
      • 2023-02-11
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多