【问题标题】:SQL Server - PIVOTSQL Server - 枢轴
【发布时间】:2010-12-01 12:07:58
【问题描述】:

我们正在开发一个 C# 应用程序,我们一直在使用 Linq to SQL 或标准 ADO(当需要性能时)与 SQL Server 一起工作。

我们有一张这样布置的桌子:

客户 ID、年/月、产品名称、数量

每个客户的每个产品都有额外的列。

我们需要像这样在数据网格中显示这些信息:

客户、年/月、产品A数量、产品B数量、产品C数量等

什么查询可以给我们这些结果?无论添加和删除什么产品,它怎么可能是动态的?我们将在 WPF 中使用 ListView 来显示数据。

我们只是以不同的方式存储信息,但他们可以随时添加/删除产品。

PIVOT 会起作用吗?

(PS - 产品名称确实在另一个表中以进行规范化,为了方便你们,我对其进行了一些更改)

【问题讨论】:

    标签: c# sql sql-server wpf tsql


    【解决方案1】:

    可以使用 sql pivot 命令,但它需要对列进行硬编码。您可以对它们进行硬编码,使用动态 sql 生成列,或者只从 sql 中获取原始数据而不使用数据透视,然后在 c# 中进行数据按摩。

    【讨论】:

      【解决方案2】:

      您可以将数据透视表与动态 SQL 一起使用。以下 T-SQL 代码取自 this article on sqlteam.com。我已尝试根据您的需要修改示例。还要注意使用动态 SQL 的危险,如果产品名称包含撇号,它可能导致 SQL 注入。

      先创建一个存储过程;

      CREATE PROCEDURE crosstab 
      @select varchar(8000),
      @sumfunc varchar(100), 
      @pivot varchar(100), 
      @table varchar(100) 
      AS
      
      DECLARE @sql varchar(8000), @delim varchar(1)
      SET NOCOUNT ON
      SET ANSI_WARNINGS OFF
      
      EXEC ('SELECT ' + @pivot + ' AS pivot INTO ##pivot FROM ' + @table + ' WHERE 1=2')
      EXEC ('INSERT INTO ##pivot SELECT DISTINCT ' + @pivot + ' FROM ' + @table + ' WHERE ' 
      + @pivot + ' Is Not Null')
      
      SELECT @sql='',  @sumfunc=stuff(@sumfunc, len(@sumfunc), 1, ' END)' )
      
      SELECT @delim=CASE Sign( CharIndex('char', data_type)+CharIndex('date', data_type) ) 
      WHEN 0 THEN '' ELSE '''' END 
      FROM tempdb.information_schema.columns 
      WHERE table_name='##pivot' AND column_name='pivot'
      
      SELECT @sql=@sql + '''' + convert(varchar(100), pivot) + ''' = ' + 
      stuff(@sumfunc,charindex( '(', @sumfunc )+1, 0, ' CASE ' + @pivot + ' WHEN ' 
      + @delim + convert(varchar(100), pivot) + @delim + ' THEN ' ) + ', ' FROM ##pivot
      
      DROP TABLE ##pivot
      
      SELECT @sql=left(@sql, len(@sql)-1)
      SELECT @select=stuff(@select, charindex(' FROM ', @select)+1, 0, ', ' + @sql + ' ')
      
      EXEC (@select)
      SET ANSI_WARNINGS ON
      

      然后尝试以下(我没有测试过,你可能需要在select语句中添加qty)

      EXECUTE crosstab 'select ProductID,CustomerID, YearMonth from sales group by ProductId', 'sum(qty)','ProductId','sales'
      

      【讨论】:

      • 我这里看的是什么速度?对于有 2200 万条记录的表,调用此存储过程的查询会非常慢吗?
      • SP 生成动态 T-SQL 代码,例如 select customername,case when productid=1 then quantity else 0 END AS Product1, case .... from order group by customername。我在生产服务器方面的经验有限,所以我不知道大约 2200 万条记录。但我建议您在 productname 列上创建索引,然后使用 sql server 压力/记录生成工具创建的记录测试速度。
      • 你的答案必须是正确的,除非有其他方法可以解决这个问题。我的问题将是速度与灵活性,所以我们将不得不试一试。
      【解决方案3】:

      如果你想尝试不涉及动态 SQL 的方法,you could go through C#

      这家伙跑了一个测试比较两者:http://weblogs.sqlteam.com/jeffs/jeffs/archive/2005/05/12/5127.aspx

      【讨论】:

      • 这基本上就是我最终要做的事情,我需要我们的解决方案非常动态,并且使用 C# 似乎对我们的目的来说足够快。我们没有在 PIVOT 和 C# 之间进行任何性能测试,PIVOT 看起来笨重且难以维护,因为我们必须手动使用列名或动态 SQL。 C# 似乎更容易处理。
      猜你喜欢
      • 1970-01-01
      • 2015-04-30
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2016-02-25
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多