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

1回のクエリで複数のarray_agg()を呼び出す

    DISTINCT 多くの場合、内部から腐敗しているクエリを修復するために適用されます。これは、多くの場合、低速であるか、正しくありません。最初に行を乗算しないでください。そうすれば、最後に不要な重複を分類する必要がなくなります。

    複数のnテーブル(「多数ある」)に一度に結合すると、結果セットの行が乗算されます。これはCROSS JOINのようなものです またはデカルト積プロキシによる

    • 2つのSQLLEFTJOINSが誤った結果を生成する

    この間違いを回避するにはさまざまな方法があります。

    最初に集約し、後で参加する

    技術的には、 one に参加している限り、クエリは機能します 集計する前に一度に複数の行を持つテーブル:

    SELECT e.id, e.name, e.age, e.streets, arrag_agg(wd.day) AS days
    FROM  (
       SELECT e.id, e.name, e.age, array_agg(ad.street) AS streets
       FROM   employees e 
       JOIN   address  ad ON ad.employeeid = e.id
       GROUP  BY e.id    -- id enough if it is defined PK
       ) e
    JOIN   workingdays wd ON wd.employeeid = e.id
    GROUP  BY e.id, e.name, e.age;
    

    主キーidを含めることもお勧めします およびGROUP BY nameだからです およびage 必ずしも一意ではありません。誤って2人の従業員をマージする可能性があります。

    ただし、 beforeのサブクエリで集計できます。 あなたが参加する、あなたが選択的なWHEREを持っていない限り、それは優れています employeesの条件 :

    SELECT e.id, e.name, e.age, ad.streets, arrag_agg(wd.day) AS days
    FROM   employees e 
    JOIN  (
       SELECT employeeid, array_agg(ad.street) AS streets
       FROM   address
       GROUP  BY 1
       ) ad ON ad.employeeid = e.id
    JOIN   workingdays wd ON e.id = wd.employeeid
    GROUP  BY e.id, e.name, e.age, ad.streets;
    

    または両方を集約します:

    SELECT name, age, ad.streets, wd.days
    FROM   employees e 
    JOIN  (
       SELECT employeeid, array_agg(ad.street) AS streets
       FROM   address
       GROUP  BY 1
       ) ad ON ad.employeeid = e.id
    JOIN  (
       SELECT employeeid, arrag_agg(wd.day) AS days
       FROM   workingdays
       GROUP  BY 1
       ) wd ON wd.employeeid = e.id;
    

    最後の1つは、通常、すべてまたはほとんどを取得した場合に高速になります ベーステーブルの行の数。

    JOINを使用することに注意してください LEFT JOINではありません 住所がない従業員を結果から削除しますまたは 営業日はありません。それは意図されているかもしれないし、意図されていないかもしれない。 LEFT JOINに切り替えます すべてを保持する 結果の従業員。

    関連するサブクエリ/LATERAL結合

    小さな選択の場合 、代わりに相関サブクエリを検討します:

    SELECT name, age
        , (SELECT array_agg(street) FROM address WHERE employeeid = e.id) AS streets
        , (SELECT arrag_agg(day) FROM workingdays WHERE employeeid = e.id) AS days
    FROM   employees e
    WHERE  e.namer = 'peter';  -- very selective
    

    または、Postgres 9.3以降では、LATERALを使用できます。 そのために参加します:

    SELECT e.name, e.age, a.streets, w.days
    FROM   employees e
    LEFT   JOIN LATERAL (
       SELECT array_agg(street) AS streets
       FROM   address
       WHERE  employeeid = e.id
       GROUP  BY 1
       ) a ON true
    LEFT   JOIN LATERAL (
       SELECT array_agg(day) AS days
       FROM   workingdays
       WHERE  employeeid = e.id
       GROUP  BY 1
       ) w ON true
    WHERE  e.name = 'peter';  -- very selective
    
    • LATERALとPostgreSQLのサブクエリの違いは何ですか?

    どちらのクエリもすべてを保持します 結果の従業員。



    1. PostgreSQLのスペースの計算と節約

    2. Java-例外の最初の原因を見つける

    3. 複数の行を更新するときにNULLタイプをキャストする

    4. PostgreSQLで行が更新されたときにタイムスタンプを更新する