繁体   English   中英

我可以使用CTE,Pivot,组合或其他方式解决此问题吗?

[英]Can I solve this with a CTE, Pivot, a combination or something else?

我被要求为我们的应用程序生成一个权限矩阵,我想知道最好的方法。

如果我有如下数据:

在此处输入图片说明

所需的输出如下所示:

在此处输入图片说明

能够动态执行此操作的最佳方法是什么-当添加新角色或菜单选项或更改标志时,它始终是最新的吗? 我感觉这是CTE领域(可能是+ Pivot),但是我现在似乎无法弯腰。

自然,还有很多很多角色和菜单选项!! (我还可以获得菜单项ID,而不仅仅是名称,显示的数据已经是我编写的查询的结果)。

从理论上讲,菜单可以具有无限深度,实际上,我们拥有的最大菜单级别是4级,

CREATE TABLE #question (
    RoleID int NOT NULL,
    RoleName varchar(50) NOT NULL,
    IsReadOnly bit NOT NULL,
    ParentMenuName varchar(100) NULL,
    MenuName varchar(100) NOT NULL,
    Regulierer bit NOT NULL,
    Station bit NOT NULL
) 


insert into #question (RoleID, RoleName, IsReadOnly, ParentMenuName, MenuName, Regulierer, Station) VALUES (1, N'Administrator', 0, NULL, N'Source Data', 0, 0)
insert into #question (RoleID, RoleName, IsReadOnly, ParentMenuName, MenuName, Regulierer, Station) VALUES (1, N'Administrator', 0, N'Source Data', N'Item', 1, 0)
insert into #question (RoleID, RoleName, IsReadOnly, ParentMenuName, MenuName, Regulierer, Station) VALUES (1, N'Administrator', 0, N'Source Data', N'Stations', 1, 0)
insert into #question (RoleID, RoleName, IsReadOnly, ParentMenuName, MenuName, Regulierer, Station) VALUES (1, N'Administrator', 0, N'Source Data', N'Cupboards', 1, 1)
insert into #question (RoleID, RoleName, IsReadOnly, ParentMenuName, MenuName, Regulierer, Station) VALUES (1, N'Administrator', 0, NULL, N'Print', 0, 0)
insert into #question (RoleID, RoleName, IsReadOnly, ParentMenuName, MenuName, Regulierer, Station) VALUES (1, N'Administrator', 0, N'Item List', N'by Item Number', 1, 0)
insert into #question (RoleID, RoleName, IsReadOnly, ParentMenuName, MenuName, Regulierer, Station) VALUES (1, N'Administrator', 0, N'by Item Number', N'ascending', 1, 0)
insert into #question (RoleID, RoleName, IsReadOnly, ParentMenuName, MenuName, Regulierer, Station) VALUES (1, N'Administrator', 0, N'by Item Number', N'descending', 1, 0)
insert into #question (RoleID, RoleName, IsReadOnly, ParentMenuName, MenuName, Regulierer, Station) VALUES (1, N'Administrator', 0, N'Item List', N'by Description', 1, 0)
insert into #question (RoleID, RoleName, IsReadOnly, ParentMenuName, MenuName, Regulierer, Station) VALUES (1, N'Administrator', 0, N'Print', N'Item List', 1, 0)
insert into #question (RoleID, RoleName, IsReadOnly, ParentMenuName, MenuName, Regulierer, Station) VALUES (2, N'Assistant', 0, NULL, N'Source Data', 0, 0)
insert into #question (RoleID, RoleName, IsReadOnly, ParentMenuName, MenuName, Regulierer, Station) VALUES (2, N'Assistant', 0, N'Source Data', N'Item', 1, 0)
insert into #question (RoleID, RoleName, IsReadOnly, ParentMenuName, MenuName, Regulierer, Station) VALUES (2, N'Assistant', 0, N'Source Data', N'Stations', 1, 0)
insert into #question (RoleID, RoleName, IsReadOnly, ParentMenuName, MenuName, Regulierer, Station) VALUES (2, N'Assistant', 1, N'Source Data', N'Cupboards', 1, 1)

我在解决方案上做了一些工作。 但是,由于时间不足,我无法完成它。 但这应该给您一个大致的想法。 毕竟,您对CTE和Pivot的看法是正确的。 为了达到结果,我将两者结合使用。

最初,我使用#question的结构定义了一个表变量(因此您将在我的代码中找到@question)。

在第一个CTE中,我创建菜单的递归树-以覆盖您提到的“动态深度”。 接下来的两个cte执行枢轴操作。 接下来,将枢轴值连接在一起并转换为“ h”,“ s”和“-”。 下一个cte准备一个空白树结构并评估菜单项的深度。 最后一个cte评估顶级标志(如果任何子值是h或s,则为X)。 最后但并非最不重要的一点是,最后一个查询根据菜单项的深度来处理菜单名称的缩进,并将admin和assistant的值加入其中。

希望这对您有所帮助。

WITH cte
AS (
    SELECT 1 lvl
        ,q.RoleID
        ,q.RoleName
        ,q.MenuName TopLvlMenu
        ,q.IsReadOnly
        ,q.ParentMenuName
        ,q.MenuName
        ,CAST(q.MenuName AS VARCHAR(MAX)) AS MenuSrt
        ,q.Regulierer
        ,q.Station
    FROM @question q
    WHERE q.ParentMenuName IS NULL

    UNION ALL

    SELECT lvl + 1 lvl
        ,c.RoleID
        ,c.RoleName
        ,c.TopLvlMenu
        ,q.IsReadOnly
        ,q.ParentMenuName
        ,q.MenuName
        ,CAST(c.MenuSrt + ' - ' + q.MenuName AS VARCHAR(MAX)) AS MenuSrt
        ,q.Regulierer
        ,q.Station
    FROM cte AS c
    JOIN @question AS q ON q.ParentMenuName = c.MenuName
        AND q.RoleID = c.RoleID
        AND q.RoleName = c.RoleName
    WHERE q.ParentMenuName IS NOT NULL
    )
,cteHospital AS (
    SELECT MenuSrt
        ,Administrator
        ,Assistant
    FROM (
        SELECT MenuSrt
            ,RoleName
            ,CAST(Regulierer AS TINYINT) AS Regulierer
        FROM cte
        ) AS j
    PIVOT(MAX(Regulierer) FOR RoleName IN (
                Administrator
                ,Assistant
                )) AS p
    )
,cteStation AS (
    SELECT MenuSrt
        ,Administrator
        ,Assistant
    FROM (
        SELECT MenuSrt
            ,RoleName
            ,CAST(Station AS TINYINT) AS Station
        FROM cte
        ) AS j
    PIVOT(MAX(Station) FOR RoleName IN (
                Administrator
                ,Assistant
                )) AS p
    )
,cteAdminAss AS (
    SELECT ISNULL(h.MenuSrt, s.MenuSrt) MenuSrt
        ,ISNULL(NULLIF(CASE 
                    WHEN h.Administrator = 1
                        THEN 'h,'
                    ELSE ''
                    END + CASE 
                    WHEN s.Administrator = 1
                        THEN 's,'
                    ELSE ''
                    END, ''), '-,') AS Administrator
        ,ISNULL(h.Administrator,0) + ISNULL(s.Administrator, 0) AS Administrator_Num
        ,ISNULL(NULLIF(CASE 
                    WHEN h.Assistant = 1
                        THEN 'h,'
                    ELSE ''
                    END + CASE 
                    WHEN s.Assistant = 1
                        THEN 's,'
                    ELSE ''
                    END, ''), '-,') AS Assistant
        ,ISNULL(h.Assistant,0) + ISNULL(s.Assistant, 0) AS Assistant_Num
    FROM cteHospital h
    FULL JOIN cteStation s ON h.MenuSrt = s.MenuSrt
    )
,cteTree AS (
    SELECT MIN(lvl) lvl
        ,MenuName
        ,MenuSrt
    FROM cte
    GROUP BY MenuName
        ,MenuSrt
    )
,cteTopLevel AS(
    SELECT c.TopLvlMenu, CASE WHEN SUM(caa.Administrator_Num) > 0 THEN 'X' ELSE '-' END Administrator, CASE WHEN SUM(caa.Assistant_Num) > 0 THEN 'X' ELSE '-' END Assistant
      FROM cteAdminAss caa
      JOIN cte c ON c.MenuSrt = caa.MenuSrt
      GROUP BY c.TopLvlMenu
    )
SELECT REPLICATE('          ', lvl - 1) + ct.MenuName AS MenuName
    ,COALESCE(ctl.Administrator, SUBSTRING(ca.Administrator, 1, LEN(ca.Administrator) - 1)) Administrator
    ,COALESCE(ctl.Assistant, SUBSTRING(ca.Assistant, 1, LEN(ca.Assistant) - 1)) Assistant
FROM cteTree ct
JOIN cteAdminAss ca ON ct.MenuSrt = ca.MenuSrt
LEFT JOIN cteTopLevel ctl ON ctl.TopLvlMenu = ct.MenuName
ORDER BY ct.MenuSrt, ct.lvl
OPTION (MAXRECURSION 0)

我认为最好不要在应用程序中使用SQL处理此问题。 许多角色和许多菜单选项的结合似乎并不适合SQL解决方案。

感谢所有为此付出时间的人。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM