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

MySQL8共通テーブル式CTE

    MySQL 8は、非再帰と再帰の両方の共通テーブル式をサポートしています。CTE(共通テーブル式)は、別のSELECT、INSERT、UPDATE、またはDELETEステートメント内で参照できる一時的な結果セットです。

    非再帰CTE

    共通テーブル式(CTE)は派生テーブルと同じですが、その宣言はFROM句ではなくクエリブロックの前に配置されます。 CTEを使用すると、サブクエリは1回だけ評価されます。共通テーブル式を使用すると、名前付きの一時結果セットを使用できます。共通テーブル式は、WITH演算子を使用してステートメント内で定義されます。

    前年に対する各年の支払いの変化率を調べたいとします。 CTEがない場合は、2つのサブクエリを作成する必要があり、それらは基本的に同じです。 MySQLはそれを検出するほど賢くなく、サブクエリは2回実行されます。

    SELECT 
    q1.years,
    q2.years AS next_year,
    q1.sum1,
    q2.sum1 AS next_sum,
    100 * (q2.sum1 - q1.sum1) / q1.sum1 AS pct
    FROM
    (SELECT YEAR(paymentDate) AS years, SUM(amount) AS sum1 FROM payments GROUP BY years) AS q1,
    (SELECT YEAR(paymentDate) AS years, SUM(amount) AS sum1 FROM payments GROUP BY years) AS q2
    WHERE
    q1.years = q2.years - 1;
    +-------+-----------+------------+------------+------------+
    | years | next_year | sum1 | next_sum | pct |
    +-------+-----------+------------+------------+------------+
    | 2003 | 2004 | 3250217.70 | 4313328.25 | 32.708903 |
    | 2004 | 2005 | 4313328.25 | 1290293.28 | -70.085901 |
    +-------+-----------+------------+------------+------------+
    2 rows in set (0.01 sec)

    非再帰CTEを使用すると、派生クエリは1回だけ実行され、再利用されます

    WITH CTE_NAME AS 
    (SELECT YEAR(paymentDate) AS years, SUM(amount) AS sum1 FROM payments GROUP BY years)
    SELECT 
    q1.years,
    q2.years AS next_year,
    q1.sum1,
    q2.sum1 AS next_sum,100 * (q2.sum1 - q1.sum1) / q1.sum1 AS pct 
    FROM 
    CTE_NAME AS q1,
    CTE_NAME AS q2 
    WHERE q1.years = q2.years - 1;
    +-------+-----------+------------+------------+------------+
    | years | next_year | sum1 | next_sum | pct |
    +-------+-----------+------------+------------+------------+
    | 2003 | 2004 | 3250217.70 | 4313328.25 | 32.708903 |
    | 2004 | 2005 | 4313328.25 | 1290293.28 | -70.085901 |
    +-------+-----------+------------+------------+------------+
    2 rows in set (0.00 sec)

    CTEを使用すると、結果は同じで、クエリ時間が50%向上し、読みやすさが向上し、複数回参照できることに気付くかもしれません。

    CTEs can refer to other CTEs:
    WITH cte1 AS (SELECT ... FROM ...), cte2 AS (SELECT ... FROM cte1 ...)
    SELECT
    FROM cte1, cte2 ...

    再帰的CTE

    再帰CTEは、それ自体を参照するCTEです。そうすることで、最初のCTEが繰り返し実行され、完全な結果が返されるまで、データのサブセットが返されます

    WITH RECURSIVE cte_name 
    AS
    (
    cte_definition -- /* seed SELECT */
    UNION ALL
    cte_definition -- /* "recursive" SELECT */ references cte_name.
    )
    -- Statement using the CTE
    SELECT *
    FROM cte_name
    を使用したステートメント

    シードSELECTは、初期データサブセットを作成するために1回実行されます。再帰的なSELECTが繰り返し実行され、完全な結果セットが取得されるまでデータのサブセットが返されます。反復によって新しい行が生成されなくなると、再帰は停止します。

    階層データトラバーサルを実行して、各従業員の管理チェーン(つまり、CEOから従業員へのパス)を含む組織図を作成するとします。再帰CTEを使用してください!再帰CTEは、階層データのクエリに最適です。

    テーブルを作成する

    CREATE TABLE mangeremp (
    id INT PRIMARY KEY NOT NULL,
    name VARCHAR(100) NOT NULL,
    man_id INT NULL,
    INDEX (man_id),
    FOREIGN KEY (man_id) REFERENCES mangeremp (id)
    );

    階層構造を取得するためにデータを挿入する

    INSERT INTO mangeremp VALUES
    (333, "waqas", NULL), # waqas is the CEO (man_id is NULL)
    (198, "ali", 333), # ali has ID 198 and reports to 333 (waqas)
    (692, "ahmed", 333), #ahmed report to waqas
    (29, "oasama", 198), #osama report to ali as alo has ref id 198
    (4610, "Mughees", 29), # Mughees report to osama
    (72, "aslam", 29),
    (123, "afrooz", 692);
    WITH RECURSIVE emp_paths (id, name, path) AS 
    (SELECT id, name, CAST(id AS CHAR(200)) 
    FROM mangeremp 
    WHERE man_id IS NULL 
    UNION ALL 
    SELECT e.id, e.name, CONCAT(ep.path, ',', e.id) 
    FROM emp_paths AS ep JOIN mangeremp AS e 
    ON ep.id = e.man_id )
    SELECT * FROM emp_paths ORDER BY path;
    +------+---------+-----------------+
    | id | name | path |
    +------+---------+-----------------+
    | 333 | waqas | 333 |
    | 198 | ali | 333,198 |
    | 29 | oasama | 333,198,29 |
    | 4610 | Mughees | 333,198,29,4610 |
    | 72 | aslam | 333,198,29,72 |
    | 692 | ahmed | 333,692 |
    | 123 | afrooz | 333,692,123 |
    +------+---------+-----------------+
    7 rows in set (0.00 sec)
    SELECT e.id, e.name, CONCAT(ep.path, ',', e.id) FROM emp_paths AS ep JOIN mangeremp AS e ON ep.id = e.man_id ---- recursive query

    再帰クエリによって生成された各行は、前の行によって生成された
    従業員に直接報告するすべての従業員を検索します。そのようなすべての従業員について、行には
    従業員ID、名前、および従業員管理チェーンが含まれます。チェーンはマネージャーのチェーンであり、
    最後に従業員IDが追加されています


    1. PostgreSQLの根性:「resjunk」とは何ですか?

    2. PostgreSQLへのリモート接続を設定する方法

    3. SQLDeveloperはスクリプトの実行をサポートしていますか?

    4. Androidでカーソルデータを使用してリスト配列を作成するにはどうすればよいですか?