SQL Server 2012。
直截了当,这就是我想要做的事情:
用户表
id username fullname
---- -------- ----------------------
1 test0001 Test User #1
2 test0002 Test User #2
3 test0003 Test User #3
4 test0004 Test User #4
标志表
id name description
--- ---------- -------------------------------------------
1 isActive true if user is currently active
2 isAdmin true if user can do Admin things
3 canEdit true if user can can edit
UserFlags表
user flag
---- ----
1 1
1 2
1 3
2 1
2 3
3 1
(user = FK to user.id, flag = FK to flag.id)
期望的结果
userId username isActive isAdmin canEdit
------ -------- -------- ------- -------
1 test0001 1 1 1
2 test0002 1 0 1
3 test0003 1 0 0
4 test0004 0 0 0
简而言之,我想将flags表中的每个标志转换为一个列,其中name
字段用作列标题。然后我想为每个用户添加一行,每列中都有一个布尔值,表示它们是否具有该特定标志。
这需要能够适应 - 例如如果添加了另一个标志,则查询结果应该有另一个列,该标题的名称为其标题。
我更喜欢在视图中执行此操作,但我可以使用表值函数。
我之前没有做过这样的事情,所以我甚至不知道从哪里开始 - 我可以在桌面上进行完全连接,最后每个用户每个标志一行,但我接着希望将每个用户的所有内容折叠成一行。
编辑其中一个关键点是能够适应" - 最佳方案是在构建响应时自动从flags表中提取所有当前定义的标志的查询。必须编辑查询并不一定是坏事,但考虑允许管理员向系统添加新标志的实例。插入新标志很容易,自动编辑存储的查询以反映这一点很难。如果这根本不可能做到,那么解释为什么会有所帮助。谢谢!
答案 0 :(得分:2)
您可以使用以下角色:
Select * from (
Select u.id, u.username, f.[name] from #user u
left join #userflags uf
on uf.[user] = u.id
left join #flags f
on uf.flag = f.id
) a
pivot (count([name]) for [name] in ([isActive],[isAdmin],[canEdit])) p
输出如下:
+----+----------+----------+---------+---------+
| id | username | isActive | isAdmin | canEdit |
+----+----------+----------+---------+---------+
| 1 | test0001 | 1 | 1 | 1 |
| 2 | test0002 | 1 | 0 | 1 |
| 3 | test0003 | 1 | 0 | 0 |
| 4 | test0004 | 0 | 0 | 0 |
+----+----------+----------+---------+---------+
如果你有动态的标志列表,请更新我的查询,如下所示:
Declare @cols1 varchar(max)
Declare @query nvarchar(max)
Select @cols1 = stuff((select distinct ','+QuoteName([name]) from #flags for xml path('')),1,1,'')
Select @query = ' Select * from (
Select u.id, u.username, f.[name] from #user u
left join #userflags uf
on uf.[user] = u.id
left join #flags f
on uf.flag = f.id
) a
pivot (count([name]) for [name] in (' + @cols1 + ')) p '
Exec sp_executesql @query
答案 1 :(得分:2)
如果你不喜欢像我这样的pivot
功能;您可以像这样使用SUM
IIF
方法
SELECT u.id
, username
, SUM(IIF(flag = 1, 1, 0)) AS isActive
, SUM(IIF(flag = 2, 1, 0)) AS isAdmin
, SUM(IIF(flag = 3, 1, 0)) AS canEdit
FROM User u
LEFT JOIN UserFlags uf ON uf.[user] = u.id
GROUP BY u.id
, username
答案 2 :(得分:0)
您可以使用case语句和子查询或使用pivot来执行此操作。它们基本上都做同样的事情。这包括我为测试而制作的表格的DDL。
declare @user_tbl table (
id int,
username nvarchar(max)
)
INSERT @user_tbl VALUES
(1,'test0001'),
(2,'test0002'),
(3,'test0003'),
(4,'test0004')
declare @userflags_tbl table(
userid int,
flag int
)
INSERT @userflags_tbl VALUES
(1,1),
(1,2),
(1,3),
(2,1),
(2,3),
(3,1)
declare @flags_tbl table(
id int
)
INSERT @flags_tbl VALUES
(1),
(2),
(3)
SELECT
userid,
username,
MAX(isActive) AS isActive,
MAX(isAdmin) AS isAdmin,
MAX(canEdit) AS canEdit
FROM (
SELECT
user_tbl.id AS userid,
user_tbl.username,
CASE
WHEN userflags_tbl.flag = 1 THEN 1
ELSE 0
END AS isActive,
CASE
WHEN userflags_tbl.flag = 2 THEN 1
ELSE 0
END AS isAdmin,
CASE
WHEN userflags_tbl.flag = 3 THEN 1
ELSE 0
END AS canEdit
FROM @user_tbl user_tbl
LEFT JOIN @userflags_tbl userflags_tbl ON
user_tbl.id = userflags_tbl.userid
LEFT JOIN @flags_tbl flags_tbl ON
userflags_tbl.flag = flags_tbl.id
)tbl
GROUP BY
userid,
username
SELECT
userid,
username,
ISNULL([1],0) AS isActive,
REPLACE(ISNULL([2],0),2,1) AS isAdmin,
REPLACE(ISNULL([3],0),3,1) AS canEdit
FROM (
SELECT
user_tbl.id AS userid,
user_tbl.username,
userflags_tbl.flag
FROM @user_tbl user_tbl
JOIN @userflags_tbl userflags_tbl ON
user_tbl.id = userflags_tbl.userid
JOIN @flags_tbl flags_tbl ON
userflags_tbl.flag = flags_tbl.id
) tbl
PIVOT (
MAX(flag)
FOR flag IN ([1],[2],[3])
) AS PivotTable