2

考虑以下(1:N)关系:

[entity: user] <------ rid key ------> [entity: rid].

将两个表中的数据视为:

select * from user;
user-id        rid-key
a-basa         a
b-basa         b
a.a-basa       a.a   
a.b-basa       a.b
a.a.a-basa     a.a.a
a.a.b-basa     a.a.b
a.b.a-basa     a.b.a
a.b.b-basa     a.b.b
a.b.b.a-basa   a.b.b.a
a.b.b.b-basa   a.b.b.b



select * from rid;

rid-key    parent-rid    enabled
a            null        true
b            null        true
a.a          a           true 
a.b          a           false
a.a.a        a.a         true
a.b.a        a.b         true
a.b.b        a.b         true
a.b.b.a      a.b.b       true
......
n rows

我需要设计一个输入 a 的单个查询(不是存储过程)user-id,并考虑以下事实:

如果用户被授予对 a 的访问权限rid,那么它也可以访问parent ridrid定的 -rid本身已启用(enabled = true).

这应该一直持续到我们到达root rid, 即。parent rid财产是null

在上面的示例中,用户可访问的摆脱列表'a.b.b.a-basa'将是:

a.b.b.a
a.b.b
a.b

a.a.a-basa

a.a.a
a.a
a

我们可以使用单个查询获取此列表吗?任何 sql 供应商都可以。

4

4 回答 4

1

甲骨文解决方案:

SQL> select u.user_id, r.rid_key, r.parent_rid, r.enabled
  2    from users u
  3         inner join rid r
  4                 on r.rid_key = u.rid_key
  5   start with u.user_id = 'a.a.a-basa'
  6   connect by prior r.parent_rid = r.rid_key and prior enabled = 'true'
  7  /

USER_ID      RID_KEY PAREN ENABL
------------ ------- ----- -----
a.a.a-basa   a.a.a   a.a   true
a.a-basa     a.a     a     true
a-basa       a       null  true

SQL> select u.user_id, r.rid_key, r.parent_rid, r.enabled
  2    from users u
  3         inner join rid r
  4                 on r.rid_key = u.rid_key
  5   start with u.user_id = 'a.b.b.a-basa'
  6   connect by prior r.parent_rid = r.rid_key and prior enabled = 'true'
  7  /

USER_ID      RID_KEY PAREN ENABL
------------ ------- ----- -----
a.b.b.a-basa a.b.b.a a.b.b true
a.b.b-basa   a.b.b   a.b   true
a.b-basa     a.b     a     false

http://sqlfiddle.com/#!4/d529f/1

于 2013-01-13T09:43:32.670 回答
1

分层数据有多种模型。大多数模型(如Adjacency List)需要对某些查询进行某种递归。通过使用物化路径模型的设计,无需递归查询即可实现您想要的。

在SQL-fiddle test-mysql的 MySQL 中测试(没有递归查询)。如果您修改字符串连接部分,它可以很容易地转换为其他 DBMS:

SELECT 
     COUNT(*)-1 AS steps_up,
     rid2.rid_key AS ancestor_rid_key
FROM 
    u2 
  JOIN
    rid 
      ON u2.rid_key = rid.rid_key
      OR u2.rid_key LIKE CONCAT(rid.rid_key, '.%')
  JOIN
    rid AS rid2 
      ON rid.rid_key = rid2.rid_key
      OR rid.rid_key LIKE CONCAT(rid2.rid_key, '.%')
WHERE
    u2.userid = 'basa'
  AND
    u2.rid_key = 'a.b.b.a' 
GROUP BY 
    rid2.rid_key, rid2.enabled 
HAVING 
    COUNT(*) + (rid2.enabled = 'true') 
  = SUM(rid.enabled = 'true') + 1 ;

它使用此视图,这不是严格需要的,但它表明正在存储您在列user.user_id中已有的数据。rid_key

CREATE VIEW u2 AS
SELECT 
    SUBSTRING_INDEX(user_id, '-', -1) AS userid
  , rid_key
FROM user ;

还有一点需要注意的是,上面的查询根本不使用该parent_rid列。而且我确信它可以进一步改进。

于 2013-01-13T11:17:42.173 回答
1

在 Oracle 中,您可以使用分层查询来实现此目的。搜索 CONNECT BY 或查看这篇文章

于 2013-01-13T09:34:16.107 回答
1

这应该让你的球滚动。答案适用于 SQL Server 2005 及更高版本

DECLARE @UsersRIDkey VARCHAR(10) = 'a.a.a'
;WITH UserCTE (userid, ridkey) AS
(
    SELECT 'a-basa',         'a'        UNION ALL
    SELECT 'b-basa',         'b'        UNION ALL
    SELECT 'a.a-basa',       'a.a'      UNION ALL
    SELECT 'a.b-basa',       'a.b'      UNION ALL
    SELECT 'a.a.a-basa',     'a.a.a'    UNION ALL
    SELECT 'a.a.b-basa',     'a.a.b'    UNION ALL
    SELECT 'a.b.a-basa',     'a.b.a'    UNION ALL
    SELECT 'a.b.b-basa',     'a.b.b'    UNION ALL
    SELECT 'a.b.b.a-basa',   'a.b.b.a'  UNION ALL
    SELECT 'a.b.b.b-basa',   'a.b.b.b'  
)
,RidCTE (ridkey, parentrid,    isenabled) AS
(
    SELECT 'a',            null,        1   UNION ALL
    SELECT 'b',            null,        1   UNION ALL
    SELECT 'a.a',          'a',         1   UNION ALL
    SELECT 'a.b',          'a',         0   UNION ALL
    SELECT 'a.a.a',        'a.a',       1   UNION ALL
    SELECT 'a.b.a',        'a.b',       1   UNION ALL
    SELECT 'a.b.b',        'a.b',       1   UNION ALL
    SELECT 'a.b.b.a',      'a.b.b',     1   
)
,RidHierarchyCTE AS
(
    SELECT *
    FROM RidCTE
    WHERE ridkey = @UsersRIDkey
    UNION ALL
    SELECT R.ridkey, R.parentrid, R.isenabled
    FROM RidHierarchyCTE    H
    JOIN RidCTE             R ON R.ridkey = H.parentrid
)
SELECT ridkey
FROM RidHierarchyCTE    
于 2013-01-13T09:34:28.973 回答