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

複数の値を持つ配列列のLEFTOUTERJOIN

    はい、重複演算子&& 配列にGINインデックスを使用できます 。特定の人物の行を検索するためにこれをクエリする場合に非常に便利です(1 )一連のアクターの中で:

    SELECT * FROM eg_assoc WHERE actors && '{1}'::int[]
    

    ただし 、クエリのロジックは逆で、eg_assocの配列にリストされているすべての人を検索します。 。 GINインデックスはいいえです ここで助けてください。 PK person.idのbtreeインデックスが必要です。 。

    適切なクエリ

    基本:

    次のクエリは、元の配列を指定どおりに保持します。 、重複する可能性のある要素と要素の元の順序を含みます。 1次元配列で機能します 。追加のディメンションは1つのディメンションに折りたたまれます。複数のディメンションを保持することはより複雑です(ただし、完全に可能です):

    WITH ORDINALITY Postgres9.4以降

    SELECT aid, actors
         , ARRAY(SELECT name
                 FROM   unnest(e.actors) WITH ORDINALITY a(id, i)
                 JOIN   eg_person p USING (id)
                 ORDER  BY a.i) AS act_names
         , benefactors
         , ARRAY(SELECT name
                 FROM   unnest(e.benefactors) WITH ORDINALITY b(id, i)
                 JOIN   eg_person USING (id)
                 ORDER  BY b.i) AS ben_names
    FROM   eg_assoc e;
    

    LATERAL クエリ

    PostgreSQLの場合9.3+

    SELECT e.aid, e.actors, a.act_names, e.benefactors, b.ben_names
    FROM   eg_assoc e
    , LATERAL (
       SELECT ARRAY( SELECT name
                     FROM   generate_subscripts(e.actors, 1) i
                     JOIN   eg_person p ON p.id = e.actors[i]
                     ORDER  BY i)
       ) a(act_names)
    , LATERAL (
       SELECT ARRAY( SELECT name
                     FROM   generate_subscripts(e.benefactors, 1) i
                     JOIN   eg_person p ON p.id = e.benefactors[i]
                     ORDER  BY i)
       ) b(ben_names);
    

    db <> fiddle こちら いくつかのバリエーションがあります。
    古い sqlfiddle

    微妙な詳細:人が見つからない場合は、ドロップされます。これらのクエリは両方とも空の配列を生成します ( '{}' )アレイ全体で人が見つからない場合。他のクエリスタイルはNULLを返します 。フィドルにバリアントを追加しました。

    関連するサブクエリ

    Postgresの場合8.4+ (ここで、 generate_subsrcipts() 導入されました):

    SELECT aid, actors
         , ARRAY(SELECT name
                 FROM   generate_subscripts(e.actors, 1) i
                 JOIN   eg_person p ON p.id = e.actors[i]
                 ORDER  BY i) AS act_names
         , benefactors
         , ARRAY(SELECT name
                 FROM   generate_subscripts(e.benefactors, 1) i
                 JOIN   eg_person p ON p.id = e.benefactors[i]
                 ORDER  BY i) AS ben_names
    FROM   eg_assoc e;
    

    Postgres 9.3でも、最高のパフォーマンスを発揮する可能性があります。
    ARRAY コンストラクター array_agg()よりも高速です 。参照:

    失敗したクエリ

    @a_horseが提供するクエリ そうです 仕事をするために、しかしそれは信頼性が低く、誤解を招き、潜在的に不正確で、不必要に高価です。

    1. 2つの無関係な結合のため、プロキシ相互結合。卑劣なアンチパターン。参照:

      DISTINCTで表面的に修正されました array_agg()内 生成された重複を排除しますが、それは本当に豚に口紅をつけています。また、オリジナルの重複を排除します この時点で違いを区別することは不可能であるため、これは潜在的に正しくありません。

    2. a_person.id = any(eg_assoc.actors) 動作 、ただし重複を排除 結果から(このクエリでは2回発生します)、指定しない限り間違っています。

    3. 元の配列要素の順序は保持されません 。これは一般的に注意が必要です。しかし、このクエリでは、アクターとベネファクターが乗算されて再び区別されるため、悪化します。これは保証 任意の順序。

    4. 外側のSELECTに列エイリアスはありません その結果、列名が重複し、一部のクライアントが失敗します(エイリアスのないフィドルでは機能しません)。

    5. min(actors) およびmin(benefactors) 役に立たない。通常は、列をGROUP BYに追加するだけです。 それらを偽造する代わりに。ただし、eg_assoc.aid とにかくPK列です(GROUP BYでテーブル全体をカバーします )、それも必要ありません。ただactors, benefactors

    結果全体を集計することは、最初から時間と労力を浪費します。基本行を乗算しないよりスマートなクエリを使用すると、それらを集約して戻す必要がありません。



    1. TRY_CAST()がSQLServerでどのように機能するか

    2. Postgresql gem install pg 0.18.4が合格、バンドルのインストールが失敗

    3. 文字列を整数に型キャスト

    4. 2列を選択し、データをマージします