需要转动帮助

时间:2012-04-14 12:41:14

标签: sql sql-server sql-server-2008 pivot pivot-without-aggregate

请帮我解决这个问题。我完全陷入困境。我有编码员阻止或其他什么。

我有下表

ID     Name        Cost     Included
----   ----------  -------  ----------
1      Package1    10.00    Yes
2      Package2    20.00    No
3      Package3    20.00    Yes

我想交叉显示此信息,要显示如下例子,表格中会有更多列。

Type        Package1     Package2       Package3
-----       ------------ -----------    ----------
Name        Package1     Package2       Package3
Cost        10.00        20.00          30.00
Included    Yes          No             Yes

4 个答案:

答案 0 :(得分:5)

在我看来,您正在尝试构建产品比较列表。如果是这样,您可以先unpivot表格,然后将各个记录合并在一起。

'transponded'部分对列进行展开。所有列必须是兼容类型或转换为一个。我选择varchar(100)。 transponded返回表,包含三列,来自ProductInfo的ID,Type作为列名,Value作为相应列的值。

通过添加另一个left join transponded tn on t1.Type = tnType and tn.ID = @parametern,选择部件将所需产品的信息连接在一起。这部分似乎很麻烦,但是当我尝试使用pivot执行此部分时,我无法按正确的顺序获取列 - 在Type中透视排序的名称。但是它需要动态的sql生成。此解决方案已修复,前提是您可以为希望一次比较的最大产品添加足够的连接。我相信它不会超过5。

= 1,= 2且= 3应由参数替换。查询应该存储在存储过程中。

; with transponded as 
(
  select ID, Type, Value
    from 
    (
      select ID, 
             Name, 
             cast (Cost as varchar(100)) Cost, 
             cast (case when Included = 1 then 'Yes' else 'No' end as varchar(100)) Included
        from ProductInfo
    ) p
      unpivot (Value for Type in (Name, Cost, Included) ) a
)
select t1.Type, 
       t1.Value Product1, 
       t2.Value Product2, 
       t3.Value Product3
  from transponded t1
  left join transponded t2
         on t1.Type = t2.Type
        and t2.id = 2
   left join transponded t3
     on t1.Type = t3.Type
    and t3.id = 3
  where t1.id = 1

简而言之,一次转发一条记录,然后按类型列加入另一条转发记录。

哦,还有here is a Sql Fiddle playground

答案 1 :(得分:1)

没有简单的方法可以做到这一点,因为枢轴需要按列聚合。鉴于在输入表中添加列会导致维护问题,这些值将不会显示到输出,直到代码在任何地方使用时都会更改,我会说你最好用存储过程执行一次,它将根据输入表的模式动态生成您正在查找的输出。

我已经使用您提供的数据演示了如何做到这一点。这些数据存储在临时表中(不是#temp,因为存储的proc不能用于临时表),因此填充:

CREATE TABLE temp (
    _key int,
    package_name varchar(50),
    cost float,
    included bit
)

INSERT INTO temp VALUES(1,'Package1',    10.00,    1)
INSERT INTO temp VALUES(2,'Package2',    20.00,    0)
INSERT INTO temp VALUES(3,'Package3',    20.00,    1)

存储过程根据@pivot_field参数检索值列表,并将这些值用作要在“类型”字段后插入的列列表。然后它将枢轴字段和所有其他字段组合在一起以生成行,一次旋转一列。程序如下:

CREATE PROCEDURE usp_get_pivot (@table_name nvarchar(255), @pivot_field nvarchar(255)) AS
BEGIN
    CREATE TABLE #temp (val nvarchar(max))

    DECLARE @sql NVARCHAR(MAX), @cols NVARCHAR(MAX), @col NVARCHAR(255)

    SET @sql = 'SELECT DISTINCT ' + @pivot_field + ' FROM ' + @table_name
    INSERT INTO #temp EXEC sp_executesql @sql;
    SET @cols = (SELECT '[' + val + '],' FROM #temp FOR XML PATH(''))
    SET @cols = SUBSTRING(@cols, 1, LEN(@cols)-1)

    SET @SQL = N'SELECT ''' + @pivot_field + ''' as [type], *
    FROM (SELECT ' + @pivot_field + ', ' + @pivot_field + ' as ' + @pivot_field + '1 FROM ' + @table_name + ') AS source_table
    PIVOT (max(' + @pivot_field + '1) FOR ' + @pivot_field + ' IN (' + @cols + ')) AS pivot_table'

    DECLARE csr CURSOR FOR 
        SELECT c.name FROM sys.columns c, sys.objects o 
        WHERE c.object_id = o.object_id AND o.name = @table_name
        AND c.name <> @pivot_field
        ORDER BY column_id

    OPEN csr
    FETCH NEXT FROM csr INTO @col
    WHILE @@FETCH_STATUS = 0
    BEGIN
        SET @sql = @sql + ' UNION ALL
        SELECT ''' + @col + ''' as [type], *
        FROM (SELECT ' + @pivot_field + ', CAST(' + @col + ' AS VARCHAR) AS ' + @col + ' FROM ' + @table_name + ') AS source_table
        PIVOT (max(' + @col + ') FOR ' + @pivot_field + ' IN (' + @cols + ')) AS pivot_table'
        FETCH NEXT FROM csr INTO @col
    END

    CLOSE csr
    DEALLOCATE csr
    DROP TABLE #temp
    EXEC sp_executesql @sql
END

您应该能够简单地将程序复制并粘贴到管理工作室,创建上面显示的数据并执行以下程序:

EXEC usp_get_pivot 'temp', 'package_name'

答案 2 :(得分:0)

如果包的数量不是静态的,我认为没有选择。 PIVOT子句只能生成静态/定义的列数。

您可以使用多个语句进行一些表到表的重写 - 但仍然需要面对静态列数。

但是你可以将其设置为例如10,然后显示最多10个包,如果包含的数量较少,则在其余列中显示NULL-s。

您也可以使用动态SQL来获得动态列数 - 但这将是一个令人头疼的问题。

如果您要将此数据导出到Excel - 请勿在SQL处进行转移 - 在Excel中进行转置(在“粘贴特殊”下)。

答案 3 :(得分:0)

基本上我现阶段所拥有的是以下内容。

        SELECT [Type],
            MAX(Beginner) AS [Beginner],
            MAX(Intermediate) AS [Intermediate],
            MAX(Advanced) AS [Advanced]
    FROM
    (
        SELECT 
            'Name' AS TYPE,
            CASE WHEN Name='Beginner' THEN Name END AS [Beginner],
            CASE WHEN Name='Intermediate' THEN Name END AS [Intermediate],
            CASE WHEN Name='Advanced' THEN Name END AS [Advanced]
        FROM Administration.Package
        UNION ALL
        SELECT 
            'Price' AS TYPE,
            CASE WHEN Name='Beginner' THEN CAST(Price AS VARCHAR) END AS [Beginner],
            CASE WHEN Name='Intermediate' THEN CAST(Price AS VARCHAR) END AS [Intermediate],
            CASE WHEN Name='Advanced' THEN CAST(Price AS VARCHAR) END AS [Advanced]
        FROM Administration.Package
    )A
    GROUP BY [Type]

但是对每一栏都有联盟感觉不对。