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

PostgreSQLで順序付けされていない配列(セット)を処理するための標準的なアプローチはありますか?

    現時点では、組み込みの方法はありません。

    配列として

    保存時に一貫して正規化する場合は、配列を常に並べ替えて重複排除して保存することにより、配列をセットとして扱うことができます。 PostgreSQLにこれを行うための組み込みのC関数があれば素晴らしいと思いますが、そうではありません。作成することを検討しましたが、C配列APIはひどい 、それで、私はたくさんの拡張機能を書いたのに、私はこれから慎重に後退しました。

    適度に不快なパフォーマンスを気にしない場合は、SQLで実行できます:

    CREATE OR REPLACE FUNCTION array_uniq_sort(anyarray) RETURNS anyarray AS $$
    SELECT array_agg(DISTINCT f ORDER BY f) FROM unnest($1) f;
    $$ LANGUAGE sql IMMUTABLE;
    

    次に、すべての保存をarray_uniq_sortへの呼び出しでラップします またはトリガーでそれを強制します。次に、配列が等しいかどうかを比較できます。 array_uniq_sortを回避できます 代わりにアプリ側で並べ替え/一意化を行った場合は、アプリからデータを要求します。

    これを行う場合はお願いします 「セット」をtext[]のような配列列として保存します 、コンマまたはスペースで区切られたテキストではありません。 この質問 を参照してください いくつかの理由で。

    配列間のキャストは基本タイプ間のキャストよりも厳密であるという事実など、いくつかの点に注意する必要があります。例:

    regress=> SELECT 'a' = 'a'::varchar, 'b' = 'b'::varchar;
     ?column? | ?column? 
    ----------+----------
     t        | t
    (1 row)
    
    regress=> SELECT ARRAY['a','b'] = ARRAY['a','b']::varchar[];
    ERROR:  operator does not exist: text[] = character varying[]
    LINE 1: SELECT ARRAY['a','b'] = ARRAY['a','b']::varchar[];
                                  ^
    HINT:  No operator matches the given name and argument type(s). You might need to add explicit type casts.
    regress=> SELECT ARRAY['a','b']::varchar[] = ARRAY['a','b']::varchar[];
     ?column? 
    ----------
     t
    (1 row)
    

    このような列は、array-containsやarray-overlapsなどの操作に対してGiSTでインデックス付けできます。配列のインデックス作成に関するPostgreSQLのドキュメントを参照してください。

    正規化された行として

    もう1つのオプションは、正規化された行を適切なキーで格納することです。私はまだarray_aggを使用します SQLの集合演算はこれに使用するのが面倒な場合があるため(特にXOR /両面集合差分演算がない場合)、それらを並べ替えて比較するために使用します。

    これは一般にEAV(エンティティ属性値)として知られています。私自身はファンではありませんが、たまにその場所があります。 valueなしで使用する場合を除きます コンポーネント。

    テーブルを作成します:

    CREATE TABLE item_attributes (
        item_id integer references items(id),
        attribute_name text,
        primary key(item_id, attribute_name)
    );
    

    各アイテムに配列値の列を持たせる代わりに、各アイテムの各セットエントリに行を挿入します。主キーによって適用される一意の制約により、特定の属性の重複を持つアイテムがないことが保証されます。属性の順序は無関係/未定義です。

    比較は、EXCEPTなどのSQL集合演算子を使用して実行できます。 、またはarray_agg(attribute_name ORDER BY attribute_name)を使用します 比較のために一貫してソートされた配列を形成します。

    インデックス作成は、特定のアイテムが特定の属性を持っているかどうかを判断することに限定されています。

    個人的には、このアプローチでは配列を使用します。

    hstore

    hstoreはキーを重複排除するため、値が空のhstoreを使用してセットを格納することもできます。 9.4のjsonb これでも機能します。

    regress=# create extension hstore;
    CREATE EXTENSION
    regress=# SELECT hstore('a => 1, b => 1') = hstore('b => 1, a => 1, b => 1');
     ?column? 
    ----------
     t
    (1 row)
    

    ただし、これはテキストタイプにのみ役立ちます。例:

    regress=# SELECT hstore('"1.0" => 1, "2.0" => 1') = hstore('"1.00" => 1, "1.000" => 1, "2.0" => 1');
     ?column? 
    ----------
     f
    (1 row)
    

    醜いと思います。繰り返しになりますが、私は配列を好みます。

    整数配列の場合のみ

    intarray 拡張機能は、配列をセットとして扱うための便利で高速な関数を提供します。これらは整数配列でのみ使用できますが、非常に便利です。




    1. VolusionAPIで結合クエリを作成する方法

    2. 'false'はmysqlの文字列と一致しますか?

    3. SQLファイアウォールを使用してPostgreSQLデータベースをサイバー攻撃から保護する方法

    4. Laravelのcreated_atとupdated_atの名前を変更します