如何在SQL Server中将行值显示为列值(只有一列值行应显示为多列)

时间:2015-07-02 00:20:52

标签: sql sql-server database

使用父表和子表的连接我得到这样的结果

  select 
      a.id, a.pname, b.childname 
  from  
      parentinfo a 
  right join 
      childinfo b on a.id = b.pid

输出:

   id   pname       childname
   --------------------------
    1   Parent1     p1child1
    1   Parent1     p1child2
    1   Parent1     p1child3
    2   Parent2     p2child1
    2   Parent2     p2child2
    3   Parent2     p3child1
    3   Parent3     p3child2
    3   Parent3     p3child3
    3   Parent3     p3child4
    4   Parent4     p4child1
    4   Parent4     p4child2
    4   Parent4     p4child3

但是,子项应显示为列,并且一个父项应仅显示一次。

可以有任意数量的孩子。

我想显示如下结果:

id  pname     child1    child2     child3     child4 
------------------------------------------------------
1   parent1   p1child1  p1child2   p1child3
2   parent2   p2child1  p2child2   
3   parent3   p3child1  p3child2   p3child3    p3child4
4   parent4   p4child1  p4child2   p4child3

如何实现这一目标?使用数据透视表或任何其他方法?

此查询将所有行转换为列

DECLARE @cols AS NVARCHAR(MAX),
        @query AS NVARCHAR(MAX)

select @cols = STUFF((SELECT ',' + QUOTENAME(childname) 
                      FROM 
                          (SELECT * 
                           FROM parentinfo a 
                           RIGHT JOIN childinfo b ON a.id = b.pid) tt
                      GROUP BY childname, id
                      ORDER BY id
                      FOR XML PATH(''), TYPE).value('.', 'NVARCHAR(MAX)') 
    ,1,1,'')

    set @query = 'SELECT ' + @cols + ' from 
         (
            select value, ColumnName
            from yourtable
        ) x
        pivot 
        (
            max(value)
            for ColumnName in (' + @cols + ')
        ) p '

     execute(@query)

1 个答案:

答案 0 :(得分:0)

以下是使用动态交叉表的一种方法:

SQL Fiddle

生成样本数据

use tempdb;
CREATE TABLE yourtable(
    id          INT,
    pname       VARCHAR(20),
    childname   VARCHAR(20)
)
INSERT INTO yourtable VALUES
(1, 'Parent1', 'p1child1'), 
(1, 'Parent1', 'p1child2'), 
(1, 'Parent1', 'p1child3'), 
(2, 'Parent2', 'p2child1'), 
(2, 'Parent2', 'p2child2'), 
(3, 'Parent3', 'p3child1'), 
(3, 'Parent3', 'p3child2'), 
(3, 'Parent3', 'p3child3'), 
(3, 'Parent3', 'p3child4'), 
(4, 'Parent4', 'p4child1'), 
(4, 'Parent4', 'p4child2'), 
(4, 'Parent4', 'p4child3');

动态交叉表

DECLARE @maxNoChildren INT
DECLARE @sql1 VARCHAR(4000) = ''
DECLARE @sql2 VARCHAR(4000) = ''
DECLARE @sql3 VARCHAR(4000) = ''

SELECT TOP 1 @maxNoChildren = COUNT(*) FROM yourtable GROUP BY id ORDER BY COUNT(*) DESC

SELECT @sql1 = 
'SELECT
    id
    ,pname
'

SELECT @sql2 = @sql2 +
'   ,MAX(CASE WHEN RN = ' + CONVERT(VARCHAR(5), N) + ' THEN childname END) AS ' + QUOTENAME('child' + CONVERT(VARCHAR(5), N)) + CHAR(10)
FROM(
    SELECT TOP(@maxNoChildren)
        ROW_NUMBER() OVER(ORDER BY (SELECT NULL))
    FROM sys.columns a
    --CROSS JOIN sys.columns b
)T(N)
ORDER BY N

SELECT @sql3 =
'FROM(
    SELECT *,
        RN = ROW_NUMBER() OVER(PARTITION BY id ORDER BY (SELECT NULL))
    FROM yourtable
)t
GROUP BY id, pname
ORDER BY id'

PRINT(@sql1 + @sql2 + @sql3)
EXEC (@sql1 + @sql2 + @sql3)

<强>结果

| id |   pname |   child1 |   child2 |   child3 |   child4 |
|----|---------|----------|----------|----------|----------|
|  1 | Parent1 | p1child1 | p1child2 | p1child3 |   (null) |
|  2 | Parent2 | p2child1 | p2child2 |   (null) |   (null) |
|  3 | Parent3 | p3child1 | p3child2 | p3child3 | p3child4 |
|  4 | Parent4 | p4child1 | p4child2 | p4child3 |   (null) |