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

を入力する単一のクエリ(ストアドプロシージャではない)を設計する必要がuser-idあり、次の事実が考慮されます。

ユーザーにへのアクセス権が与えられている場合は、与えられたのへridのアクセスも可能です-それ自体が有効になっていますparent ridridrid(enabled = true).

これは、に到達するまで続く必要がありroot ridます。parent ridプロパティはnullです。

'a.b.b.a-basa'上記の例では、ユーザーがアクセスできるridのリストは次のようになります。:

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

とのためにa.a.a-basa

a.a.a
a.a
a

単一のクエリを使用してこのリストを取得できますか?どのSQLベンダーでも問題ありません。

4

4 に答える 4

1

階層データにはいくつかのモデルがあります。ほとんどのモデル(隣接リストなど)では、一部のクエリに対して何らかの再帰が必要です。マテリアライズドパスモデルを使用する設計では、再帰クエリなしで必要なことが可能です。

MySQL(再帰クエリがない)のSQL-fiddletest-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 ;

もう1つの注意点は、上記のクエリはparent_rid列をまったく使用しないということです。そして、それはさらに改善できると確信しています。

于 2013-01-13T11:17:42.173 に答える
1

Oracleでは、階層クエリを使用してこれを実現できます。CONNECT BYを検索するか、この記事をご覧ください。

于 2013-01-13T09:34:16.107 に答える
1

これでボールが転がります。答えはSQLServer2005以降で機能します

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 に答える
1

Oracleソリューション:

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 に答える