1

请帮我解决一下这个。我完全被困住了。我有编码器块或其他东西。

我有下表

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

4 回答 4

5

在我看来,您正在尝试建立一个产品比较列表。如果这是真的,您可能会先取消透视表,然后将各个记录连接在一起。

'transponded' 部分取消旋转列。所有列必须是兼容类型或转换为一种。我选择 varchar(100)。transponded 返回三列的表,ID 来自 ProductInfo,Type 作为列名,Value 作为对应列的值。

选择部分通过添加另一个将尽可能多的产品信息连接在一起left join transponded tn on t1.Type = tnType and tn.ID = @parametern。这部分似乎很麻烦,但是当我尝试使用枢轴执行此部分时,我未能以正确的顺序获取列 - 类型中的枢轴排序名称。然而,它需要动态的 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

In short, transpond one record at time and join to another transponded record by Type column.

Oh, and here is a Sql Fiddle playground.

于 2012-04-14T15:45:23.173 回答
1

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

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

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'
于 2012-04-14T15:11:44.580 回答
0

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

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

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

您也可以使用动态 SQL 来获得动态列数——但这会让人头疼。

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

于 2012-04-14T13:13:37.470 回答
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]

但是对每一列都使用联合是不对的。

于 2012-04-14T13:14:50.417 回答