如何在 SQL Server 2005 中对 sql 表进行尴尬的旋转?
Posted
技术标签:
【中文标题】如何在 SQL Server 2005 中对 sql 表进行尴尬的旋转?【英文标题】:How to make awkward pivot of sql table in SQL Server 2005? 【发布时间】:2011-01-26 20:57:06 【问题描述】:我必须从 SQL Server 轮换给定的表,但正常的数据透视不起作用(据我尝试)。那么有人知道如何将表格旋转成所需的格式吗?
只是为了使问题更复杂,给定标签的列表可能会有所不同,并且可能会在任何给定时间出现新的标签名称。
给定数据
ID | Label | Numerator | Denominator | Ratio
---+-----------------+-------------+---------------+--------
1 | LabelNameOne | 41 | 10 | 4,1
1 | LabelNameTwo | 0 | 0 | 0
1 | LabelNameThree | 21 | 10 | 2,1
1 | LabelNameFour | 15 | 10 | 1,5
2 | LabelNameOne | 19 | 19 | 1
2 | LabelNameTwo | 0 | 0 | 0
2 | LabelNameThree | 15 | 16 | 0,9375
2 | LabelNameFive | 19 | 19 | 1
2 | LabelNameSix | 17 | 17 | 1
3 | LabelNameOne | 12 | 12 | 1
3 | LabelNameTwo | 0 | 0 | 0
3 | LabelNameThree | 11 | 12 | 0,9167
3 | LabelNameFour | 12 | 12 | 1
3 | LabelNameSix | 0 | 1 | 0
想要的结果
ID | ValueType | LabelNameOne | LabelNameTwo | LabelNameThree | LabelNameFour | LabelNameFive | LabelNameSix
---+-------------+--------------+--------------+----------------+---------------+---------------+--------------
1 | Numerator | 41 | 0 | 21 | 15 | |
1 | Denominator | 10 | 0 | 10 | 10 | |
1 | Ratio | 4,1 | 0 | 2,1 | 1,5 | |
2 | Numerator | 19 | 0 | 15 | | 19 | 17
2 | Denominator | 19 | 0 | 16 | | 19 | 17
2 | Ratio | 1 | 0 | 0,9375 | | 1 | 1
3 | Numerator | 12 | 0 | 11 | 12 | | 0
3 | Denominator | 12 | 0 | 12 | 12 | | 1
3 | Ratio | 1 | 0 | 0,9167 | 1 | | 0
【问题讨论】:
【参考方案1】:这应该可以解决您的问题。这真的是一个 UNPIVOT 和一个 PIVOT。请注意,您必须使数据保持一致,因为 UNPIVOT 会将所有数据放在同一列中。
请注意,我必须在内部动态 SQL 中重新创建/重新填充表变量 - 通常在处理永久表时不需要这样做。
SET NOCOUNT ON ;
DECLARE @pivot_cols AS varchar(max) ;
DECLARE @src AS TABLE
(
ID int NOT NULL
,Label varchar(14) NOT NULL
,Numerator int NOT NULL
,Denominator int NOT NULL
,Ratio decimal(5, 4) NOT NULL
) ;
DECLARE @label_order AS TABLE
(
Label varchar(14) NOT NULL
,Sort int NOT NULL
)
INSERT INTO @src
VALUES (1, 'LabelNameOne', 41, 10, 4.1) ;
INSERT INTO @src
VALUES (1, 'LabelNameTwo', 0, 0, 0) ;
INSERT INTO @src
VALUES (1, 'LabelNameThree', 21, 10, 2.1) ;
INSERT INTO @src
VALUES (1, 'LabelNameFour', 15, 10, 1.5) ;
INSERT INTO @src
VALUES (2, 'LabelNameOne', 19, 19, 1) ;
INSERT INTO @src
VALUES (2, 'LabelNameTwo', 0, 0, 0) ;
INSERT INTO @src
VALUES (2, 'LabelNameThree', 15, 16, 0.9375) ;
INSERT INTO @src
VALUES (2, 'LabelNameFive', 19, 19, 1) ;
INSERT INTO @src
VALUES (2, 'LabelNameSix', 17, 17, 1) ;
INSERT INTO @src
VALUES (3, 'LabelNameOne', 12, 12, 1) ;
INSERT INTO @src
VALUES (3, 'LabelNameTwo', 0, 0, 0) ;
INSERT INTO @src
VALUES (3, 'LabelNameThree', 11, 12, 0.9167) ;
INSERT INTO @src
VALUES (3, 'LabelNameFour', 12, 12, 1) ;
INSERT INTO @src
VALUES (3, 'LabelNameSix', 0, 1, 0) ;
INSERT INTO @label_order
VALUES ('LabelNameOne', 1) ;
INSERT INTO @label_order
VALUES ('LabelNameTwo', 2) ;
INSERT INTO @label_order
VALUES ('LabelNameThree', 3) ;
INSERT INTO @label_order
VALUES ('LabelNameFour', 4) ;
INSERT INTO @label_order
VALUES ('LabelNameFive', 5) ;
INSERT INTO @label_order
VALUES ('LabelNameSix', 6) ;
WITH Labels
AS (
SELECT DISTINCT
src.Label
,ISNULL(label_order.Sort, 0) AS Sort
FROM @src AS src
LEFT JOIN @label_order AS label_order
ON src.label = label_order.label
)
SELECT @pivot_cols = COALESCE(@pivot_cols + ',', '') + QUOTENAME(Label, '[')
FROM Labels
ORDER BY Sort
,Label ;
DECLARE @template AS varchar(max) ;
SET @template = '
DECLARE @src AS TABLE
(
ID int NOT NULL
,Label varchar(14) NOT NULL
,Numerator int NOT NULL
,Denominator int NOT NULL
,Ratio decimal(5, 4) NOT NULL
) ;
INSERT INTO @src
VALUES (1, ''LabelNameOne'', 41, 10, 4.1) ;
INSERT INTO @src
VALUES (1, ''LabelNameTwo'', 0, 0, 0) ;
INSERT INTO @src
VALUES (1, ''LabelNameThree'', 21, 10, 2.1) ;
INSERT INTO @src
VALUES (1, ''LabelNameFour'', 15, 10, 1.5) ;
INSERT INTO @src
VALUES (2, ''LabelNameOne'', 19, 19, 1) ;
INSERT INTO @src
VALUES (2, ''LabelNameTwo'', 0, 0, 0) ;
INSERT INTO @src
VALUES (2, ''LabelNameThree'', 15, 16, 0.9375) ;
INSERT INTO @src
VALUES (2, ''LabelNameFive'', 19, 19, 1) ;
INSERT INTO @src
VALUES (2, ''LabelNameSix'', 17, 17, 1) ;
INSERT INTO @src
VALUES (3, ''LabelNameOne'', 12, 12, 1) ;
INSERT INTO @src
VALUES (3, ''LabelNameTwo'', 0, 0, 0) ;
INSERT INTO @src
VALUES (3, ''LabelNameThree'', 11, 12, 0.9167) ;
INSERT INTO @src
VALUES (3, ''LabelNameFour'', 12, 12, 1) ;
INSERT INTO @src
VALUES (3, ''LabelNameSix'', 0, 1, 0) ;
WITH src_conformed
AS (
SELECT ID
,Label
,CAST (Numerator AS decimal(10, 4)) AS Numerator
,CAST (Denominator AS decimal(10, 4)) AS Denominator
,CAST (Ratio AS decimal(10, 4)) AS Ratio
FROM @src
),
UNPIVOTED
AS (
SELECT *
FROM src_conformed UNPIVOT ( Val FOR Col IN (Numerator, Denominator, Ratio) ) AS unpvt
)
SELECT *
FROM UNPIVOTED PIVOT ( SUM(Val) FOR Label IN (@pivot_cols) ) AS pvt
ORDER BY ID
,Col ;' ;
SET @template = REPLACE(@template, '@pivot_cols', @pivot_cols) ;
EXEC (@template) ;
【讨论】:
这看起来很棒。即使您将我的测试数据添加为临时表也绝对很棒。如果我能给你比我已经拥有的更多的代表(+1 并标记为正确),我会这样做。万分感谢。 成功使用您的版本后,我只有一个小问题,我无法解决。结果三行的顺序是按字母顺序排列的,但我想在一个 ID 内获得顺序 Num...、Den...、Ratio。任何想法如何得到它? @Oliver 使用我用来制作@label_order 表的相同技术。我注意到了这一点,并认为您会看到我如何解决列顺序并使用相同的技术。 对不起,你是对的。我已经看到了,但是由于我在具体问题中不需要它,这是我删除的第一个问题。当我需要它时,我只是不记得了。 @Oliver 没问题 - 此示例代码可能比您系统中所需的代码更长且更复杂,因为您已经拥有所有这些东西的永久表。【参考方案2】:select
id,
'Numerator' as ValueType,
case when label = labelNameOne then Numerator else 0 end as LabelNameOne,
case when label = labelNameTwo then Numerator else 0 end as LabelNameTwo,
case when label = labelNameTree then Numerator else 0 end as LabelNameTree,
case when label = labelNameFour then Numerator else 0 end as LabelNameFour,
case when label = labelNameFive then Numerator else 0 end as LabelNameFive,
case when label = labelNameSix then Numerator else 0 end as LabelNameSix
union All
...与分母类似的查询...
union all
...与比率类似的查询...
【讨论】:
是的,这是我的尝试之一,但不幸的是标签列表可能会有所不同,因此我无法准确命名案例陈述中的标签。你知道有什么方法可以从select distinct Label from table
这样的给定列表中创建案例吗?【参考方案3】:
您寻求的是动态交叉表。简短的回答是,如果没有一些笨拙的动态 SQL,它就无法在 T-SQL 中完成。霍伊尔的回答是,您应该在报告工具或中间层中透视数据。
【讨论】:
是的,这就是我目前正在运行的方向(在 C++ 中对自己进行操作),但我想,也许有人直接在 SQL 中知道另一种方式。以上是关于如何在 SQL Server 2005 中对 sql 表进行尴尬的旋转?的主要内容,如果未能解决你的问题,请参考以下文章
使用 SSMA 将 Access 2007 数据库应用程序迁移到 SQL Server 2005 - 问题
连接SQL2005出现SQL Server 无法连接到服务器 提示 服务器:消息11,级别16,状态1 怎么解决啊
如何转换SQL Server 2008数据库到SQL Server 2005