MySQLクエリツリー構造方式

MySQLクエリツリー構造方式

MySQL クエリツリー構造

1. ツリー構造について

ここに画像の説明を挿入

このタイプの構造のデータは通常、テーブル構造内に id や parentId などの自己関連付けフィールドを必要とします。場合によっては、クエリの効率を向上させるために、index などの冗長フィールドを追加できます。index の値は、すべての親ディレクトリの id 文字列のセットです。

ツリー構造データの組み立てについては、プログラム内で再帰的に完全なツリーを構築する書き方が一般的です。単純にSQLを使用する方法はあまり使われません。以下に2つの方法の例を示します。

2. MySQLでカスタム関数を定義する方法

MySQL カスタム関数とは: 集計関数、日付関数などはすべて MySQL 関数です。ここで定義する関数は、それらと同じように使用できますが、定義されたデータベースでのみ使用できます。カスタム関数はストアド プロシージャに似ていますが、違いは、関数は 1 つの値のみを返し、結果セットを返すことができないことです。

2.1 テストデータを作成する

テーブル「tree」を作成します(
  `id` bigint(11) NOT NULL,
  `pid` bigint(11) NULL デフォルト NULL,
  `name` varchar(255) 文字セット utf8 COLLATE utf8_general_ci NULL デフォルト NULL,
  BTREE を使用した主キー (`id`)
) ENGINE = InnoDB CHARACTER SET = utf8 COLLATE = utf8_general_ci ROW_FORMAT = Dynamic;
`tree` VALUES (1, 0, '中国') に INSERT INTO します。
`tree` VALUES (2, 1, '四川省') に INSERT INTO します。
`tree` VALUES (3, 2, '成都') に INSERT INTO します。
`tree` VALUES (4, 3, '武侯区') に INSERT INTO します。
`tree` VALUES (5, 4, 'Red Archway') に INSERT INTO します。
INSERT INTO `tree` VALUES (6, 1, '広東省');
INSERT INTO `tree` VALUES (7, 1, '浙江省');
`tree` VALUES (8, 6, 'Guangzhou') に INSERT INTO します。

2.2 ノードの下にあるすべての子ノードを取得する

関数 `GET_CHILD_NODE`(rootId varchar(100)) を作成します。   
戻り値 varchar(2000)  
始める   
str varchar(2000) を宣言します。  
cid varchar(100) を宣言します。   
str = '$' を設定します。   
cid = rootId を設定します。   
cidがnullでない場合に実行   
    SET str = concat(str, ',', cid);   
    group_concat(id) を tree から cid に選択します。ここで、FIND_IN_SET(pid, cid);   
終了しながら;   
文字列を返します。   
終わり

カスタム関数の呼び出し

FIND_IN_SET(id, GET_CHILD_NODE(2))のツリーから*を選択します。 

ここに画像の説明を挿入

2.3 ノードのすべての親ノードを取得する

関数 `GET_PARENT_NODE`(rootId varchar(100)) を作成します。   
戻り値 varchar(1000)   
始める   
fid varchar(100) default '' を宣言します。   
str varchar(1000) default rootIdを宣言します。   
  
rootIdがnullでない場合に   
    SET fid =(SELECT pid FROM tree WHERE id = rootId);   
    fidがnullでない場合   
        SET str = concat(str, ',', fid);   
        rootId = fid を設定します。   
    それ以外   
        rootId = fid を設定します。   
    終了の場合;   
終了しながら;   
str を返します。  
終わり

カスタム関数の呼び出し

FIND_IN_SET(id, GET_PARENT_NODE(5))のツリーから*を選択します。 

ここに画像の説明を挿入

3. Oracleデータベース方式

再帰ツリー クエリを完了するには、start with connect by prior ステートメントを使用するだけです。詳細については、関連情報を参照してください。

4. プログラムコードは再帰的にツリーを構築する

ここでは完全なコードは示しません。再帰メソッドは非常にシンプルです。まず、すべてのツリー ノードを見つけ、次に TreeNode クラスの add メソッドを使用してすべての子ノードを再帰的に追加します。コアコードは次のとおりです。

パブリッククラス TreeNodeDTO {
    
    プライベート文字列ID;
    プライベート文字列親ID;
    プライベート文字列名;
    プライベートList<TreeNodeDTO> children = new ArrayList<>();
    パブリック void add(TreeNodeDTO ノード) {
        if ("0".equals(node.parentId)) {
            this.children.add(ノード);
        } そうでない場合 (node.parentId.equals(this.id)) {
            this.children.add(ノード);
        } それ以外 {
         	//add() を再帰的に呼び出して子ノードを追加します for (TreeNodeDTO tmp_node : children) {
                tmp_node.add(ノード);
            }
        }
    }
 }

5. hashMapを使用すると、1回の走査のみで済みます

ツリー生成を完了できます: 5つ星の推奨

リスト<TreeNodeDTO> リスト = dbMapper.getNodeList();
ArrayList<TreeNodeDTO> rootNodes = 新しいArrayList<>();
Map<Integer, TreeNodeDTO> map = new HashMap<>();
(TreeNodeDTO ノード: リスト) {
    ノードをマップします。
    整数の親Id = node.getParentId();
    // 親ノードがあるかどうかを判定します(親ノードがない場合は親メニューです)
    (親IDが'0'に等しい)の場合
        ルートノードを追加します。
        // 親メニューではないメニューを検索し、その親メニュー ID をコレクションに含めます
    } そうでない場合 (map.containsKey(parentId)){
        map.get(parentId).getChildren().add(ノード);
    }
}

ツリー構造情報を含むMySQLクエリ

Oracleには、ツリー構造情報を直接照会できる関数アプリケーションがあります。たとえば、次のツリー構造を持つ組織メンバー構造がある場合、いずれかのノードの下にあるすべてのノード情報を照会したい場合、

Oracleでは、次の構文を使用して直接クエリを実行できます。

まずはCONNECT BY PRIOORから

しかし、MySQL にはそのような構文はありません。

このようなデータ構造情報も照会したい場合はどうすればよいでしょうか?独自の関数を定義できます。上記の情報をデータベースに初期化します。まず、この情報を格納するテーブルを作成します。ID には自身の ID 情報が、PARENT_ID には親の ID 情報が格納されます。

テーブル「company_inf」を作成します(
  `ID` varchar(32) COLLATE utf8mb4_unicode_ci デフォルト NULL,
  `NAME` varchar(255) COLLATE utf8mb4_unicode_ci デフォルト NULL,
  `PARENT_ID` varchar(32) COLLATE utf8mb4_unicode_ci デフォルト NULL
)

次にテーブル内の情報を初期化します

company_inf に VALUES ('1','ゼネラルマネージャー Wang Damazi','1') を挿入します。
company_inf に VALUES ('2','R&D マネージャー Liu Daquezi','1') を挿入します。
company_inf に VALUES ('3','営業部長 Ma Erlangzi','1') を挿入します。
company_inf に VALUES ('4','財務マネージャー Zhao Santuozi','1') を挿入します。
company_inf に VALUES ('5','秘書従業員 J','1') を挿入します。
company_inf に VALUES ('6','R&D チームリーダー Wu Dabangchui','2') を挿入します。
INSERT INTO company_inf VALUES ('7','Zheng Laoliu、R&Dグループ2の責任者','2');
company_inf に VALUES ('8','営業担当者 G','3') を挿入します。
company_inf に VALUES ('9','営業担当者 H','3') を挿入します。
company_inf に VALUES ('10','財務担当者 I','4') を挿入します。
company_inf に VALUES ('11','開発者 A','6') を挿入します。
company_inf に VALUES ('12','開発者 B','6') を挿入します。
company_inf に値 ('13'、'開発者 C'、'6') を挿入します。
company_inf に値 ('14'、'開発者 D'、'7') を挿入します。
company_inf に VALUES ('15','Developer E','7') を挿入します。
company_inf に値 ('16'、'開発者 F'、'7') を挿入します。

例えば、R&DマネージャーのLiu Daquziの配下の従業員全員を照会したい場合、Oracleで次のように記述できます。

  選択*
  T_PORTAL_AUTHORITY より
  ID='1' で開始
  以前のIDで接続 = PARENT_ID

MySQLでは、次のカスタム関数が必要です。

関数 getChild(parentId VARCHAR(1000)) を作成します。
VARCHAR(1000)を返します
始める
    oTemp VARCHAR(1000) を宣言します。
    oTempChild VARCHAR(1000) を宣言します。
    oTemp を '' に設定します。
    oTempChild = 親IDを設定します。
    oTempChildがnullでない場合に実行
        oTemp != '' の場合
            oTemp を連結して設定します (oTemp,',',oTempChild);
        それ以外
            oTemp = oTempChild を設定します。
        終了の場合;
        SELECT group_concat(ID) INTO oTempChild FROM company_inf where parentId<>ID and FIND_IN_SET(parent_id,oTempChild)>0;
    終了しながら;
oTemp を返します。
終わり

すると、このようにクエリできます

company_inf から * を選択し、 FIND_IN_SET(ID,getChild('2'));

現時点では、クエリをチェックして取得した情報は、Liu Daquzi の配下の従業員情報すべてです。

上記は私の個人的な経験です。参考になれば幸いです。また、123WORDPRESS.COM を応援していただければ幸いです。

以下もご興味があるかもしれません:
  • Mysqlツリー再帰クエリの実装方法
  • MySQL ですべての子ノードのツリーのようなクエリを実装する方法
  • MySQL マルチレベル構造ツリー検索の紹介
  • MySQL 再帰クエリ ツリー テーブル子ノード、親ノードの特定の実装

<<:  CentOS 8 に Docker をインストールする詳細なチュートリアル

>>:  Vue.js アプリケーションのパフォーマンス最適化分析 + ソリューション

推薦する

JS オブジェクトのコピー (ディープ コピーとシャロー コピー)

目次1. 浅いコピー1. Object.assign(ターゲット、ソース、ソース...) 2. スプ...

Ubuntu システムでタイムゾーンと時刻を変更する方法

Linux コンピュータには 2 つの時間があります。1 つはハードウェア時間 (BIOS に記録さ...

Javascript 仮想 DOM の詳細な説明

目次仮想DOMとは何ですか?なぜ仮想DOMが必要なのでしょうか?仮想 DOM はどのようにして実際の...

同じ日の最初の3つのデータを取得するためのMySQLタイムラインデータ

テーブルデータを作成する テーブル `praise_info` を作成します ( `id` bigi...

Vue コンポーネント化の一般的な方法: コンポーネント値の転送と通信

関連する知識ポイント親コンポーネントから子コンポーネントに値を渡す子コンポーネントから親コンポーネン...

フロントエンドパフォーマンス最適化に関する補足記事

序文私は、Web サイトのフロントエンド パフォーマンス最適化のための JavaScript と C...

CSSを使用してすべての子要素を選択する方法の詳細な説明

CSS を使用してすべての子要素を再帰的に選択するにはどうすればよいですか?以下の記事では、CSS ...

CentOS 7 で rpm パッケージを使用して MySQL 5.7.18 をインストールする

最近、MySQL を使っています。Linux での mysql-installation という記事...

DockerでSpring Bootアプリケーションを実行する方法

ここ数日、dockerでSpring Bootアプリケーションを実行する方法を勉強してきました。以前...

Vue の 2 択タブバー切り替えの新しいアプローチ

問題の説明プロジェクトに取り組んでいるときに、タブ バーの切り替え効果を作成する必要がある場合があり...

Linux での Python スクリプトの自動起動とスケジュール起動の詳細な手順

1. Pythonは起動時に自動的に実行されますPython の自己起動スクリプトがauto.pyで...

Dockerコンテナに入る方法と出る方法

1 Dockerサービスを開始するまず、docker サービスを開始する方法を知っておく必要がありま...

ページ内のリストプルダウン効果を実現するための純粋なCSS

次のような効果がよく見られます。 そうです、ページ上でよく使われる「展開と折りたたみ」のインタラクシ...

nginx ログを elasticsearch にインポートする方法の例

nginx ログは filebeat によって収集され、logstash に渡され、logstash...

Docker初心者が初めてよく使うコマンドを試してみる練習記録

Docker を正式に使用する前に、まず Docker でよく使用されるコマンドに慣れておきましょう...