Pet*_*eed 3 sql t-sql common-table-expression sql-server-2008
我们有一个角色继承结构,而不是最高级别的过滤,它假设默认情况下每个人都获得最低级别的角色,图形描述如下:
role.Everyone //lowest level; everyone gets this role
role.Applications // everyone assigned this role gets applications && everyone roles
role.Databases // everyone assigned this role gets databases && applications && everyone roles
role.SoftwareSubscriber
role.Client_All // etc.
role.Client
role.ITClient
role.Client
role.NewsService // everyone assigned this role gets NewsService && Client && Everyone
// && Client_All roles, since Client is also a child of Client_All
role.ClientDeliverable // etc.
role.Employee
role.Corporate
role.Marketing
role...
...
Run Code Online (Sandbox Code Playgroud)
我会检索所有“父母”(真的,孩子,但无论如何)和他们任何给定角色的递归父母。例如,我希望有一个查询要求 的父母role.Databases返回role.Applications和role.Everyone。同样,我期望的父母要求查询role.NewsService到的回报role.Client,role.Everyone和role.Client_All,因为role.Client是两个孩子role.Everyone和role.Client_All。
我尝试在MSDN 的 CTE 示例之后对查询建模,如下所示,但我无法获得所有递归父项。任何人都可以将我的 CTE 查询引向正确的方向吗?
CREATE TABLE #ATTRIBASSIGN
(
ATTRIBID int not null
, ITEMID int not null
, ITEMCLASS VARCHAR(10) NOT NULL DEFAULT ('ATTRIB')
, CONSTRAINT PK_ATTRIBASSIGN_ATTRIBID_ITEMID_ITEMCLASS PRIMARY KEY (ATTRIBID, ITEMID, ITEMCLASS)
)
CREATE TABLE #ATTRIBPROP
(
ATTRIBID int not null identity(1,1) primary key
, ATTRIBNAME VARCHAR(50) not null
)
GO
INSERT INTO #ATTRIBPROP (ATTRIBNAME)
VALUES ('role.Databases'), ('role.Applications'), ('role.Everyone'), ('role.Client_All'), ('role.Employee'), ('role.SoftwareSubscriber'),
('role.Client'), ('role.ITClient'), ('role.NewsService'), ('role.ClientDeliverable'), ('role.Corporate'), ('role.Marketing')
GO
INSERT INTO #ATTRIBASSIGN (ATTRIBID, ITEMID)
SELECT A.ATTRIBID, B.ATTRIBID
FROM #ATTRIBPROP A
CROSS JOIN #ATTRIBPROP B
WHERE A.ATTRIBNAME = 'role.Everyone'
AND B.ATTRIBNAME = 'role.Applications'
UNION
SELECT A.ATTRIBID, B.ATTRIBID
FROM #ATTRIBPROP A
CROSS JOIN #ATTRIBPROP B
WHERE A.ATTRIBNAME = 'role.Everyone'
AND B.ATTRIBNAME = 'role.Client_All'
UNION
SELECT A.ATTRIBID, B.ATTRIBID
FROM #ATTRIBPROP A
CROSS JOIN #ATTRIBPROP B
WHERE A.ATTRIBNAME = 'role.Everyone'
AND B.ATTRIBNAME = 'role.Client'
UNION
SELECT A.ATTRIBID, B.ATTRIBID
FROM #ATTRIBPROP A
CROSS JOIN #ATTRIBPROP B
WHERE A.ATTRIBNAME = 'role.Everyone'
AND B.ATTRIBNAME = 'role.Employee'
UNION
SELECT A.ATTRIBID, B.ATTRIBID
FROM #ATTRIBPROP A
CROSS JOIN #ATTRIBPROP B
WHERE A.ATTRIBNAME = 'role.Applications'
AND B.ATTRIBNAME = 'role.Databases'
UNION
SELECT A.ATTRIBID, B.ATTRIBID
FROM #ATTRIBPROP A
CROSS JOIN #ATTRIBPROP B
WHERE A.ATTRIBNAME = 'role.Applications'
AND B.ATTRIBNAME = 'role.SoftwareSubscriber'
UNION
SELECT A.ATTRIBID, B.ATTRIBID
FROM #ATTRIBPROP A
CROSS JOIN #ATTRIBPROP B
WHERE A.ATTRIBNAME = 'role.Client_All'
AND B.ATTRIBNAME = 'role.Client'
UNION
SELECT A.ATTRIBID, B.ATTRIBID
FROM #ATTRIBPROP A
CROSS JOIN #ATTRIBPROP B
WHERE A.ATTRIBNAME = 'role.Client_All'
AND B.ATTRIBNAME = 'role.ITClient'
UNION
SELECT A.ATTRIBID, B.ATTRIBID
FROM #ATTRIBPROP A
CROSS JOIN #ATTRIBPROP B
WHERE A.ATTRIBNAME = 'role.Client'
AND B.ATTRIBNAME = 'role.NewsService'
UNION
SELECT A.ATTRIBID, B.ATTRIBID
FROM #ATTRIBPROP A
CROSS JOIN #ATTRIBPROP B
WHERE A.ATTRIBNAME = 'role.Client'
AND B.ATTRIBNAME = 'role.ClientDeliverable'
UNION
SELECT A.ATTRIBID, B.ATTRIBID
FROM #ATTRIBPROP A
CROSS JOIN #ATTRIBPROP B
WHERE A.ATTRIBNAME = 'role.Employee'
AND B.ATTRIBNAME = 'role.Corporate'
UNION
SELECT A.ATTRIBID, B.ATTRIBID
FROM #ATTRIBPROP A
CROSS JOIN #ATTRIBPROP B
WHERE A.ATTRIBNAME = 'role.Employee'
AND B.ATTRIBNAME = 'role.Marketing'
GO
WITH RoleStructure (parentRole, currentRole, Level)
AS
(
SELECT B.ITEMID, B.ATTRIBID, 0 level
FROM #ATTRIBASSIGN B
WHERE B.ATTRIBID NOT IN
(
SELECT ITEMID
FROM #ATTRIBASSIGN C
WHERE B.ATTRIBID = C.ITEMID
)
AND B.ITEMCLASS = 'attrib'
UNION ALL
SELECT B.ITEMID, B.ATTRIBID, D.level - 1
FROM #ATTRIBASSIGN B
INNER JOIN RoleStructure D ON B.ATTRIBID = D.parentRole
WHERE B.ITEMCLASS = 'attrib'
)
SELECT B.ATTRIBNAME, C.ATTRIBNAME, level
FROM RoleStructure A
INNER JOIN #ATTRIBPROP B ON A.parentRole = B.ATTRIBID
INNER JOIN #ATTRIBPROP C ON A.currentRole = C.ATTRIBID
Run Code Online (Sandbox Code Playgroud)
感谢提供全面的 SQL 和示例数据 - 这使得构建答案变得更加容易!看起来您的主要错误是在父母和孩子之间混淆了自己。我认为您过多地关注结构如何“反向”并超越了您的想法。我对您的 SQL 进行了两次主要编辑以使其正常工作。
1) 翻转父项和当前项。在“AttribAssign”中,我将 ATTRIBID 视为“父级”,将“ITEMID”视为“子级”,因此您有一个很好的常规树。我也最终翻转了 UNION 的第二半(递归部分)来排队
2)我没有过滤“锚”数据集。额外的 10 行是必要的,以保持递归如您所愿。我这样做是因为您希望为任何父/子组合输出一行,而不管递归级别如何。您的原始表格具有所有“直接”组合。您希望扩展每个“直接”以包含 N+1 个间接级别。您的查询给出的只是“直接”关系。通过保留所有原始链接,我们可以建立该集合以更好地找到所有链接,而不管间接级别如何。令人困惑,是的,但它有效。
;WITH RoleStructure (parentRole, currentRole, Level)
AS
(
SELECT B.ATTRIBID, B.ITEMID, 0 level
FROM #ATTRIBASSIGN B
WHERE B.ITEMCLASS = 'attrib'
UNION ALL
SELECT D.parentRole, B.ITEMID, D.level - 1
FROM #ATTRIBASSIGN B
INNER JOIN RoleStructure D ON B.ATTRIBID = D.currentRole
WHERE B.ITEMCLASS = 'attrib'
)
SELECT a.parentRole, a.currentRole, B.ATTRIBNAME, C.ATTRIBNAME, level
FROM RoleStructure A
INNER JOIN #ATTRIBPROP B ON A.parentRole = B.ATTRIBID
INNER JOIN #ATTRIBPROP C ON A.currentRole = C.ATTRIBID
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
3118 次 |
| 最近记录: |