我有以下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 |
+-------+-------+-------+
请注意,用户名在每一列中都按顺序排列。希望有人能指出正确的方向。
答案 0 :(得分:4)
如果您的部门列表是动态的,则仅处理3列#然后,我们必须使用动态SQL来处理n
列数...但是,正如您在示例中对3进行硬编码一样,我假设3。
Demo使用rank()但row_number也有效;但是,每一种情况都会产生不同的结果。
我没有考虑边缘情况,例如,如果您的数据在同一部门中有重复的用户名……这些会合并为1还是要查看多行,或者数据不可能吗?
使用max和按row_number分组可以使我们获得非空行。 关于原因..每个行号对于部门中的每个名称都是唯一的。边缘情况可能会引起问题,因为行号是根据部门中的有序用户分配的,因此所有类似的行都将合并为一个。
您不需要多个CTE,我们可以按部门进行分区。 分区中名称的排序依据可确保名称按字母顺序排序。然后我们按末尾的行号排序。
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 |
+---+-------+-------+-------+