如何使这些选择的组和成员更简单,更有效?

时间:2012-06-15 20:25:42

标签: sql sql-server-2008 sql-server-2005

背景

我有一个表,用户表和一个 group_members 表。

groups { group_ varchar(50) not null, etc... }
users  { user_id varchar(50) not null, etc... }
group_members { group_ varchar(50 not null, member varchar(50) not null }

我的要求声明一个群组可以将其他群组作为成员。用户需要被视为他们所属的任何组的所有组的成员 例如,请考虑以下表中的以下数据:

group_members              | groups         | users    |
========================== | ============== | ======== |
group_          member     | group_         | user_id  |
-------------------------- | -------------- | -------- |
'SYSTEM_ADMIN'  'OE_ADMIN' | 'SYSTEM_ADMIN' | 'USER    |
'SYSTEM_ADMIN'  'AR_ADMIN' | 'OE_ADMIN'     |          |
'SYSTEM_ADMIN'  'USER'     | 'AR_ADMIN'     |          |

我想问这个问题的结果 “用户”是哪个群组的成员?应为

member
==============
'SYSTEM_ADMIN'
'OE_ADMIN'
'AR_ADMIN'

问题

我已经构建了以下查询并向我提供了所需的结果,但它看起来有点复杂。

WITH GM
AS (
    SELECT GROUP_, MEMBER FROM group_members 
       WHERE member IN (SELECT group_ FROM groups)
)
SELECT group_ FROM group_members WHERE member = 'USER'
UNION
SELECT MEMBER AS GROUP_ FROM GM 
   WHERE group_ in (SELECT group_ FROM group_members WHERE member = 'USER')

有关如何使此查询更简单或更简洁的任何建议吗?

2 个答案:

答案 0 :(得分:0)

您的递归CTE看起来很好。

它是如何表现的?

我认为没有任何重要的方法可以让它变得更简单 - 递归的CTE总是看起来很乱。

WHERE IN等同于JOIN,但我认为它不具有可读性,执行计划应该非常相同。

您的根行可以在递归之前表示为CTE,但它在可读性方面实际上不会节省太多:

WITH root AS ()
     ,CTE AS ()
SELECT FROM ROOT 
    UNION
SELECT FROM CTE

在任何情况下,您都可以将它放在视图或内联表值函数(带参数)中,以便从系统中的其他位置轻松使用,这样您就不必非常了解它。 / p>

我为层次结构所做的一些事情是构建一个更高性能的扁平化/非规范化版本,并在触发器或计时器上更新它,并将其用作只读性能增强器。例如,在我们构建的技术支持系统中,我们可以在层次结构中标记问题,我们在选择子项时填写所有父项(printer-> hp-> laserjet),因此很容易查询任何版本的Windows上的hp打印机问题或Windows XP上的laserjets问题。

答案 1 :(得分:0)

根据@Cade Roux的回答,进一步的反思引导我进入以下存储过程

ALTER PROCEDURE GetUserGroups
@user_id varchar(50)
AS
BEGIN
SET NOCOUNT ON;

SELECT group_ FROM group_members WHERE member = @user_id
UNION
SELECT MEMBER AS GROUP_ FROM group_members
WHERE group_ IN (SELECT group_ FROM group_members WHERE member = @user_id) 
      AND member != @user_id
END

这简化了原始查询,并正确满足了我要求获取@user_id所属的组名列表以及作为顶级组成员的组的名称。

此代码仅允许组中的组达到一个级别。