В SQL, как я могу повернуть таблицу, а также получить подробную информацию? - PullRequest
0 голосов
/ 30 ноября 2018

У меня есть следующие тестовые данные TSQL:

IF OBJECT_ID('dbo.emp') IS NOT NULL
    DROP TABLE dbo.emp;
CREATE TABLE dbo.emp (name NVARCHAR(10), dept NVARCHAR(10));
GO

INSERT INTO dbo.emp (name, dept)
VALUES
(N'user1', N'dept1'),
(N'user2', N'dept1'),
(N'user3', N'dept2'),
(N'user4', N'dept2'),
(N'user5', N'dept2'),
(N'user6', N'dept3');

Как я могу повернуть данные, а также получить детали каждой строки?Результат, который я хочу получить:

+-------+-------+-------+
| dept1 | dept2 | dept3 |
+-------+-------+-------+
| user1 | user3 | user6 |
| user2 | user4 | NULL  |
| NULL  | user5 | NULL  |
+-------+-------+-------+

Сейчас я пришел с этим запросом:

WITH
    cte1 AS (
                SELECT name                              dept1,
                       ROW_NUMBER() OVER (ORDER BY name) row
                FROM dbo.emp
                WHERE
                    dept = 'dept1'
            ),
    cte2 AS (
                SELECT name                              dept2,
                       ROW_NUMBER() OVER (ORDER BY name) row
                FROM dbo.emp
                WHERE
                    dept = 'dept2'
            ),
    cte3 AS (
                SELECT name                              dept3,
                       ROW_NUMBER() OVER (ORDER BY name) row
                FROM dbo.emp
                WHERE
                    dept = 'dept3'
            )
SELECT cte1.dept1,
       cte2.dept2,
       cte3.dept3
FROM cte1
     FULL OUTER JOIN cte2
         ON cte2.row = cte1.row
     FULL OUTER JOIN cte3
         ON cte3.row = cte1.row;

Это дает мне правильный результат.Однако, когда я изменяю демонстрационные данные на:

IF OBJECT_ID('dbo.emp') IS NOT NULL
    DROP TABLE dbo.emp;
CREATE TABLE dbo.emp (name NVARCHAR(10), dept NVARCHAR(10));
GO

INSERT INTO dbo.emp (name, dept)
VALUES
(N'user1', N'dept1'),
(N'user2', N'dept1'),
(N'user3', N'dept2'),
(N'user4', N'dept2'),
(N'user5', N'dept2'),
(N'user6', N'dept3'),
(N'user7', N'dept3'),
(N'user8', N'dept3');

Упомянутый ниже запрос дает:

+-------+-------+-------+
| dept1 | dept2 | dept3 |
+-------+-------+-------+
| user1 | user3 | user6 |
| user2 | user4 | user7 |
| NULL  | user5 | NULL  |
| NULL  | NULL  | user8 |
+-------+-------+-------+

Это не то, что я хочу.Результат, который я ожидаю:

+-------+-------+-------+
| dept1 | dept2 | dept3 |
+-------+-------+-------+
| user1 | user3 | user6 |
| user2 | user4 | user7 |
| NULL  | user5 | user8 |
+-------+-------+-------+

Обратите внимание, что имена пользователей упорядочены в каждом столбце.Надеюсь, кто-то может указать мне правильное направление.

1 Ответ

0 голосов
/ 30 ноября 2018

Это обрабатывает только 3 столбца, если ваш список отделов является динамическим #, тогда мы должны использовать динамический SQL для обработки числа n столбцов ... Но, как вы жестко закодировали 3 в вашем примере, 3 я предположил.

Демо использует rank (), но работает также row_number;Тем не менее, крайние случаи могут давать разные результаты с каждым, однако.

Я не рассматривал крайние случаи, например, если у вас есть дубликаты имен пользователей в одних и тех же отделах в ваших данных ... Будут ли они объединены в 1 или вы хотите увидеть несколько строк, или это невозможно сданные?

Использование max и группировки по row_number - это то, что дает нам ненулевые строки.почему .. каждый номер строки будет уникальным для каждого имени в отделе.Тем не менее, крайние случаи могут вызвать проблемы, так как номер строки назначается на основе упорядоченных пользователей в отделах, все подобные строки будут объединены в один.

Вам не нужны множественные cte, которые мы можем просто разделить на dept.Упорядочение по именам внутри раздела обеспечивает упорядочение имен в алфавитном порядке.затем сортируем по номеру строки в конце..

CREATE TABLE emp53564443 (name NVARCHAR(10), dept NVARCHAR(10));

INSERT INTO emp53564443 (name, dept)
VALUES
(N'user1', N'dept1'),
(N'user2', N'dept1'),
(N'user3', N'dept2'),
(N'user4', N'dept2'),
(N'user5', N'dept2'),
(N'user6', N'dept3'),
(N'user7', N'dept3'),
(N'user8', N'dept3');

with cte as (SELECT A.*
                 , row_number() over (partition by dept order by name) RnDEPT
             FROM emp53564443 A)

SELECT max(Case when dept='dept1' then name end) dept1
     , max(case when dept='dept2' then name end) dept2
     , max(case when dept='dept3' then name end) dept3
FROM cte
GROUP BY rnDept
ORDER BY rnDept

Дает нам:

+---+-------+-------+-------+
|   | dept1 | dept2 | dept3 |
+---+-------+-------+-------+
| 1 | user1 | user3 | user6 |
| 2 | user2 | user4 | user7 |
| 3 | NULL  | user5 | user8 |
+---+-------+-------+-------+
...