Sqlserver
 sql >> Baza danych >  >> RDS >> Sqlserver

Zdobądź samotnego rodzica ze wszystkimi dziećmi w jednym rzędzie

Twój przykład jest bliski przestawiania, ale nie sądzę, aby funkcja przestawna była użyteczna w tym przypadku.

Zmieniłem nazwę twojego przykładu, aby użyć „osoba-wydziału” zamiast „dziecko-rodzic”, aby zachować zdrowie psychiczne.

A więc pierwsze tabele i trochę danych

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 ;

Teraz chcę spłaszczyć model, użyję tabeli tymczasowej, ponieważ mam zmienne tabeli – ale widok „prawdziwych tabel” też byłby dobry.

/*  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

Dynamiczne kolumny to dynamiczne zapytanie, skomponuję je wiersz po wierszu do tabeli

/* 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

A teraz połącz wszystkie wiersze zapytania w zmienną i wykonaj

/* 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

A oto wynik:



  1. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. serwer sql Wstaw zbiorczo csv z danymi zawierającymi przecinek

  2. SQL - bezpiecznie prześlij BIGINT do INT

  3. Unikaj tych 4 typowych błędów DBA

  4. SQL Server:jak uzyskać nazwę bazy danych jako parametr w procedurze składowanej

  5. Uzyskiwanie identyfikatora wiersza, który zaktualizowałem w SQL Server