获得包含所有孩子的单亲父母

时间:2009-12-24 11:51:29

标签: sql-server sql-server-2005 pivot

让我假设我在SQL(server 2005)中设置了父子结构:

CREATE TABLE parent (Id INT IDENTITY PRIMARY KEY, Name VARCHAR(255))
CREATE TABLE child (Id INT IDENTITY PRIMARY KEY, parentId INT, Name VARCHAR(255))

insert into parent select 'parent with 1 child'
insert into parent select 'parent with 2 children'

insert into child(name, parentid) select 'single child of parent 1', 1
insert into child(name, parentid) select 'child 1 of 2 of parent 2', 2
insert into child(name, parentid) select 'child 2 of 2 of parent 2', 2

有没有办法在每个父级返回一行,并将其子项作为列?像:

parent.Id,parent.Name,child(1).Id,child(1).Name,child(2).Id,child(2).Name

开始于:

select * from parent p
    left outer join child c1 on c1.parentid = p.id

5 个答案:

答案 0 :(得分:4)

你的例子接近于旋转,但我不认为枢轴功能在这个上是可用的。

我已将您的示例重命名为使用“部门人”而不是“儿童父母”,只是为了保持理智。

所以,第一张表和一些数据

DECLARE @Department TABLE
  ( 
   DepartmentID int
  ,DepartmentName varchar(50)
  )
DECLARE @Person TABLE
  ( 
   PersonID int
  ,PersonName varchar(50)
  ,DepartmentID int
  )

INSERT  INTO @Department
  ( DepartmentID, DepartmentName )
 SELECT 1, 'Accounting' UNION
 SELECT 2, 'Engineering' UNION
 SELECT 3, 'Sales' UNION
 SELECT 4, 'Marketing' ;

INSERT  INTO @Person
  ( PersonID, PersonName, DepartmentID )
 SELECT 1, 'Lyne', 1 UNION
 SELECT 2, 'Damir', 2 UNION
 SELECT 3, 'Sandy', 2 UNION
 SELECT 4, 'Steve', 3 UNION
 SELECT 5, 'Brian', 3 UNION
 SELECT 6, 'Susan', 3 UNION
 SELECT 7, 'Joe', 4 ;

现在我想要展平模型,我会使用临时表因为我有表变量 - 但是对“真实表”的观点也会很好。

/*  Create a table with:
    DepartmentID, DepartmentName, PersonID, PersonName, PersonListIndex

 This could be a view instead of temp table. 
*/
IF object_id('tempdb.dbo.#tmpTbl','U') IS NOT NULL
 DROP TABLE #tmpTbl

;
WITH  prs
        AS ( SELECT PersonID
                   ,PersonName
                   ,DepartmentID
                   ,row_number() OVER ( PARTITION BY DepartmentID ORDER BY PersonID ) AS [PersonListIndex]
             FROM   @Person
           ),
      dptprs
        AS ( SELECT d.DepartmentID
                   ,d.DepartmentName
                   ,p.PersonID 
                   ,p.PersonName
                   ,p.PersonListIndex
             FROM   @Department AS d
                    JOIN prs AS p ON p.DepartmentID = d.DepartmentID
           )
SELECT * INTO #tmpTbl FROM dptprs

-- SELECT * FROM #tmpTbl

动态列表示动态查询,我会逐行将其组成表

/* Table to compose dynamic query */
DECLARE @qw TABLE
  ( 
   id int IDENTITY(1, 1)
  ,txt nvarchar(500)
  )

/* Start composing dynamic query */
INSERT  INTO @qw ( txt ) VALUES  ( 'SELECT' ) 
INSERT  INTO @qw ( txt ) VALUES  ( '[DepartmentID]' )
INSERT  INTO @qw ( txt ) VALUES  ( ',[DepartmentName]' ) ;


/* fetch max number of employees in a department */
DECLARE @i int ,@m int
SET @m = (SELECT max(PersonListIndex) FROM #tmpTbl)

/* Compose dynamic query */
SET @i = 1
WHILE @i <= @m 
  BEGIN  
      INSERT  INTO @qw ( txt )
            SELECT  ',MAX(CASE [PersonListIndex] WHEN '
                    + cast(@i AS varchar(10)) + ' THEN [PersonID] ELSE NULL END) AS [Person_'
                    + cast(@i AS varchar(10)) + '_ID]'

      INSERT  INTO @qw ( txt )
            SELECT  ',MAX(CASE [PersonListIndex] WHEN '
                    + cast(@i AS varchar(10)) + ' THEN [PersonName] ELSE NULL END) AS [Person_'
                    + cast(@i AS varchar(10)) + '_Name]'  

    SET @i = @i + 1
  END

/* Finish the dynamic query */
INSERT  INTO @qw (txt) VALUES ( 'FROM #tmpTbl' )
INSERT  INTO @qw (txt) VALUES ( 'GROUP BY [DepartmentID], [DepartmentName]' )
INSERT  INTO @qw (txt) VALUES ( 'ORDER BY [DepartmentID]' )

-- SELECT * FROM @qw

现在,将所有查询行连接到一个变量并执行

/* Create a variable with dynamic sql*/
DECLARE @exe nvarchar(4000)
SET @exe=''
SELECT  @exe = @exe + txt + ' ' FROM @qw ORDER BY id

/* execute dynamic sql */
EXEC master..sp_executesql @exe

结果如下:

alt text

答案 1 :(得分:3)

如果你想要一个不同的外观,试试这个

示例数据

declare @parent table (Id INT IDENTITY PRIMARY KEY, Name VARCHAR(255))
declare  @child table (Id INT IDENTITY PRIMARY KEY, parentId INT, Name VARCHAR(255))

insert into @parent select 'parent with 1 child'
insert into @parent select 'parent with 2 children'
insert into @child(name, parentid) select 'single child of parent 1', 1
insert into @child(name, parentid) select 'child 1 of 2 of parent 2', 2
insert into @child(name, parentid) select 'child 2 of 2 of parent 2', 2

<强>查询

select p.Id as ParentId,p.Name as ParentName
    ,stuff((select ',  ' + 'child(' + cast(c.Id as varchar(10)) + ') : ' +  c.Name 
    from @child c where c.parentId = p.id for xml path('')),1,1,'') 'Child(id):Child Names'
    from @parent p
group by
p.Id,p.Name

<强>输出

ParentId    ParentName  Child(id):Child Names
1   parent with 1 child   child(1) : single child of parent 1
2   parent with 2 children    child(2) : child 1 of 2 of parent 2,  child(3) : child 2 of 2 of parent 2

答案 2 :(得分:1)

答案 3 :(得分:1)

尝试动态旋转

测试数据

declare @parent table (Id INT IDENTITY PRIMARY KEY, Name VARCHAR(255))
declare  @child table (Id INT IDENTITY PRIMARY KEY, parentId INT, Name VARCHAR(255))

insert into @parent select 'parent with 1 child'
insert into @parent select 'parent with 2 children'
insert into @child(name, parentid) select 'single child of parent 1', 1
insert into @child(name, parentid) select 'child 1 of 2 of parent 2', 2
insert into @child(name, parentid) select 'child 2 of 2 of parent 2', 2

<强>查询

declare @col_list varchar(max)
declare @dynquery nvarchar(max)
select
 c.Id as ChildId
 , p.Id as ParentId
 ,p.Name as ParentName
 ,c.Name as ChildName 
into #t from @parent p join @child c on p.Id = c.parentId 
select @col_list = stuff(cols,1,1,'') from
(select distinct ',[' + cast(ChildName as varchar(50)) + ']' 
 from #t for xml path(''))X(cols)
set @dynquery = 'select * from #t pivot ( max(ChildId) for ChildName in (' + @col_list + ') ' + ') as pvt'
EXEC  master..sp_executesql @dynquery 
drop table #t

<强>输出:

ParentId ParentName child 1 of 2 of parent 2 child 2 of 2 of parent 2 single child of parent 1
1 parent with 1 child NULL NULL 1
2 parent with 2 children 2 3 NULL

答案 4 :(得分:1)

在看了Damir Sudarevic的回答后,我想出了这个:(参见我对表结构的质疑)

declare @family table (parentid int , parentname varchar(255), child1id int, child1name varchar(255), child2id int, child2name varchar(255))

insert into @family(parentid, parentname)
select id, name from parent

update @family set child1id = c.id, child1name = c.name
from @family f, child c 
where c.parentid = f.parentid

update @family set child2id = c.id, child2name = c.name
from @family f, child c 
where c.parentid = f.parentid
and not exists
    (select child1id from @family where child1id = c.id)

select * from @family