オペレーター
これは@Danielの巧妙な演算子に基づいています。
その間、多相型を使用して関数/演算子のコンボを作成します。次に、すべてのタイプで機能します -コンストラクトのように。
そして、関数を作成しますIMMUTABLE
。
CREATE FUNCTION is_distinct_from(anyelement, anyelement)
RETURNS bool LANGUAGE sql IMMUTABLE AS
'SELECT $1 IS DISTINCT FROM $2';
CREATE OPERATOR <!> (
PROCEDURE = is_distinct_from(anyelement,anyelement),
LEFTARG = anyelement
, RIGHTARG = anyelement
);
symbolhoundを使用したクイック検索が空になったため、オペレーター<!>
はどのモジュールでも使用されていないようです。
場合あなたは、この演算子をたくさん使用しようとしている、あなたは(問い合わせプランナを支援するためにいくつかのより多くのそれを肉付けかもしれないlosthorseコメントで提案されているように)。まず、クエリオプティマイザーを支援するためにCOMMUTATOR
and NEGATOR
句を追加できます。CREATE OPERATOR
上からこれを置き換えます:
CREATE OPERATOR <!> (
PROCEDURE = is_distinct_from(anyelement,anyelement),
LEFTARG = anyelement
, RIGHTARG = anyelement
, COMMUTATOR = <!>
, NEGATOR = =!=
);
追加します:
CREATE FUNCTION is_not_distinct_from(anyelement, anyelement)
RETURNS bool LANGUAGE sql IMMUTABLE AS
'SELECT $1 IS NOT DISTINCT FROM $2';
CREATE OPERATOR =!= (
PROCEDURE = is_not_distinct_from(anyelement,anyelement),
LEFTARG = anyelement
, RIGHTARG = anyelement
, COMMUTATOR = =!=
, NEGATOR = <!>
);
ただし、追加の句は、当面のユースケースには役立たず、プレーンインデックスはまだ使用されません。それを達成するためにはるかに洗練されています。(試していません。)詳細については、マニュアルの「オペレーター最適化情報」の章をお読みください。
テストケース
質問のテストケースは、配列内のすべての値が同一である場合にのみ成功します。質問('{null,A}'::text[]
)の配列の場合、結果は常にTRUEです。それは意図したものですか?「IS DISTINCT FROM ALL」のテストを追加しました:
SELECT foo
, foo <!> ANY ('{null,A}'::text[]) AS chk_any
, foo <!> ALL ('{null,A}'::text[]) AS chk_all
FROM (
VALUES ('A'),('Z'),(NULL)
) z(foo)
foo | chk_any | chk_all
-----+---------+---------
A | t | f
Z | t | t
| t | f
標準演算子による代替
foo IS DISTINCT FROM ANY (test_arr) -- illegal syntax
ほとんどに翻訳することができます
foo = ALL (test_arr) IS NOT TRUE
foo = ALL (test_arr)
収量...
TRUE
..すべての要素がfoo
FALSE
..である場合いずれかのNOT NULL
要素が<> foo
NULL
..であり、少なくとも1つの要素がIS NULL
あり、要素がない場合<> foo
だから、残りのコーナーケースはどこに
- foo IS NULL
- と test_arr
何が、で構成されていNULL
要素。
いずれかを除外できる場合は、完了です。したがって、次の場合は単純なテストを使用します
-列が定義されている場合NOT NULL
。
- またはあなたが知っている配列がすべてのNULLになることはありません。
それ以外の場合、さらにテストします。
AND ('A' = ALL(test_arr) IS NOT NULL OR
'B' = ALL(test_arr) IS NOT NULL OR
foo IS NOT NULL)
場所'A'
と'B'
は、個別の値です。SOに関するこの関連質問の下の説明と代替案:
配列はPostgreSQLのすべてNULLです
繰り返しますがtest_arr
、たとえば空の文字列''
などに存在できない値について知っている場合は、引き続き単純化できます。
AND ('' = ALL(test_arr) IS NOT NULL OR
foo IS NOT NULL)
すべての組み合わせを確認するための完全なテストマトリックスを次に示します。
SELECT foo, test_arr
, foo = ALL(test_arr) IS NOT TRUE AS test_simple
, foo = ALL(test_arr) IS NOT TRUE
AND ('A' = ALL(test_arr) IS NOT NULL OR
'B' = ALL(test_arr) IS NOT NULL OR
foo IS NOT NULL) AS test_sure
FROM (
VALUES ('A'),('Z'),(NULL)
) v(foo)
CROSS JOIN (
VALUES ('{null,A}'::text[]),('{A,A}'),('{null,null}')
) t(test_arr)
foo | test_arr | test_simple | test_sure
-----+-------------+-------------+-----------
A | {NULL,A} | t | t
A | {A,A} | f | f -- only TRUE case
A | {NULL,NULL} | t | t
Z | {NULL,A} | t | t
Z | {A,A} | t | t
Z | {NULL,NULL} | t | t
| {NULL,A} | t | t
| {A,A} | t | t
| {NULL,NULL} | t | f -- special case
これはAndriyのEXCEPT
ソリューションよりも少し冗長ですが、かなり高速です。