从连接表上的连接返回继承的值?

时间:2012-09-20 20:50:23

标签: sql sql-server inheritance join common-table-expression

为简单起见,假设我有以下表格:

role

id  name        inherits
----------------------------------
1   Base        null
2   Role2       1
3   Role3       1
4   Role3Child  3

item

id  name            org_id      
----------------------------------
1   item1            4210
2   item2            4210
3   item3            4210
4   item4            4210
5   item5            4210
6   item6            4210


role_item_junction

id  role_id     item_id      item_value
----------------------------------
1   1       1            true
2   1       2            false
3   2       3            D
4   3       3            F
5   4       4            12

role_id 4这里通过继承自role_id 1继承的role_id 3继承了所有项目。

当我查询与role_id 4有关的所有项目时,我想返回:

  1. 分配给role_id 4和item_value
  2. 的所有项目
  3. role_id 4继承的所有项及其item_values
  4. 某个org_id
  5. 中的所有其他项目

    如何编写一个返回role_id 4应该有权访问的所有项的查询?当我查询role_id 4时,我希望输出看起来类似于以下内容:

    id(item.id) org_id      name(item.name)     item_value
    ------------------------------------------------------------------
    1       4210        item1           true
    2       4210        item2           false
    3       4210        item3           F
    4       4210        item4           12
    5       4210        item5           NULL <--not in the junction table
    6       4210        item6           NULL <--not in the junction table
    

    不知道如何从左连接返回联结表中的继承项值:

    @orgid varchar(5) = '4210',
    @roleid int = 4
    
    
    SELECT item.*, ri.item_value AS selected_item_value
    --SNIP LOTS OF OTHER COLUMNS RETURNED
    
    FROM item
    LEFT JOIN role_item AS ri ON item.id = ri.item_id 
    AND ri.role_id = @roleid
    ???? how do I return the ri.item_value of items that roleid 4 inherits from?
    --SNIP LOTS OF OTHER IRRELEVANT JOINS
    
    WHERE 
    ((@orgid IS NULL or @orgid = '') or item.org_id = @orgid) AND
    item.date_archived IS NULL 
    AND ri.date_archived IS NULL
    

1 个答案:

答案 0 :(得分:1)

在没有递归CTE的情况下,我想不出一个简单的方法来解决它,但这应该有效:

;WITH roleCascaded AS
(SELECT id, id as inherits
FROM role
UNION ALL
SELECT r2.id, r1.inherits
FROM role r1 
INNER JOIN roleCascaded r2 on r1.id = r2.inherits AND r1.inherits IS NOT NULL
)
SELECT item.*, ri.item_value AS selected_item_value
FROM item
LEFT OUTER JOIN role_item AS ri ON item.id = ri.item_id 
LEFT OUTER JOIN roleCascaded AS rc ON rc.inherits = ri.role_id AND rc.id = @roleid
WHERE 
((@orgid IS NULL or @orgid = '') or item.org_id = @orgid) AND
item.date_archived IS NULL 
AND ri.date_archived IS NULL