Sqlserver
 sql >> Base de Dados >  >> RDS >> Sqlserver

Obter um pai solteiro com todos os filhos em uma única linha


Seu exemplo está perto de pivotar, mas não acho que a funcionalidade pivot seja utilizável neste.

Eu renomeei seu exemplo para usar "department-person", em vez de "child-parent", apenas para manter minha sanidade.

Então, primeiras tabelas e alguns dados
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 ;

Agora eu quero achatar o modelo, vou usar uma tabela temporária porque tenho variáveis ​​de tabela -- mas uma visão em "tabelas reais" também seria bom.
/*  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

Colunas dinâmicas significa consulta dinâmica, vou compor linha por linha em uma tabela
/* 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

E agora, concatene todas as linhas de consulta em uma variável e execute
/* 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

E aqui está o resultado: