sql >> データベース >  >> RDS >> Mysql

循環結合、再帰検索の防止

    MySQL 8.0を使用する場合 またはMariaDB10.2 (またはそれ以上)再帰CTE(一般的なテーブル式)を試すことができます 。

    次のスキーマとデータを想定しています:

    CREATE TABLE `list_relation` (
      `child_id`  int unsigned NOT NULL,
      `parent_id` int unsigned NOT NULL,
      PRIMARY KEY (`child_id`,`parent_id`)
    );
    insert into list_relation (child_id, parent_id) values
        (2,1),
        (3,1),
        (4,2),
        (4,3),
        (5,3);
    

    次に、child_id = 1で新しい行を挿入しようとします およびparent_id = 4 。しかし、それは循環関係を作成します( 1-> 4-> 2-> 1 および1->4-> 3-> 1 )、これを防ぎたい。逆の関係がすでに存在するかどうかを確認するには、次のクエリを使用できます。これにより、リスト4のすべての親が表示されます。 (継承/推移的な親を含む):

    set @new_child_id  = 1;
    set @new_parent_id = 4;
    
    with recursive rcte as (
      select *
      from list_relation r
      where r.child_id = @new_parent_id
      union all
      select r.*
      from rcte
      join list_relation r on r.child_id = rcte.parent_id
    )
    select * from rcte
    

    結果は次のようになります:

    child_id | parent_id
           4 |         2
           4 |         3
           2 |         1
           3 |         1
    

    デモ

    結果から、リスト1であることがわかります。 リスト4の親の1つです 、新しいレコードを挿入しません。

    リスト1かどうかだけを知りたいので 結果に、最後の行を

    に変更できます。
    select * from rcte where parent_id = @new_child_id limit 1
    

    またはに

    select exists (select * from rcte where parent_id = @new_child_id)
    

    ところで:同じクエリを使用して、冗長な関係を防ぐことができます。child_id = 4のレコードを挿入するとします。 およびparent_id = 1リスト4なので、これは冗長になります すでにリスト1を継承しています リスト2 およびリスト3 。次のクエリはそれを示します:

    set @new_child_id  = 4;
    set @new_parent_id = 1;
    
    with recursive rcte as (
      select *
      from list_relation r
      where r.child_id = @new_child_id
      union all
      select r.*
      from rcte
      join list_relation r on r.child_id = rcte.parent_id
    )
    select exists (select * from rcte where parent_id = @new_parent_id)
    

    また、同様のクエリを使用して、継承されたすべてのアイテムを取得できます。

    set @list = 4;
    
    with recursive rcte (list_id) as (
      select @list
      union distinct
      select r.parent_id
      from rcte
      join list_relation r on r.child_id = rcte.list_id
    )
    select distinct i.*
    from rcte
    join item i on i.list_id = rcte.list_id
    


    1. Azureサーバーレスの概要

    2. MySQLでのUPPER()関数のしくみ

    3. MySQLdbパッケージをインストールするにはどうすればいいですか? (ImportError:setuptoolsという名前のモジュールがありません)

    4. IntentServiceがアプリケーションUIをフリーズしています