결합 포스트 그레스 방법 IS DISTINCT FROM
으로 ANY
또는 동일한 결과를 얻기의 다른 깔끔한 방법은?
select count(*)
from (select 'A' foo union all select 'Z' union all select null) z
where foo <> any(array[null, 'A']);
count
-------
1
(1 row)
select count(*)
from (select 'A' foo union all select 'Z' union all select null) z
where foo is distinct from any(array[null, 'A']);
ERROR: syntax error at or near "any"
LINE 3: where foo is distinct from any(array[null, 'A']);
^
답변
아마도 이것 처럼 :
select foo
, exists (values (null), ('A') except select foo) chk_any
, not exists (values (null), ('A') intersect select foo) chk_all
from ( values ('A'),('Z'),(null) ) z(foo);
foo | chk_any | chk_all
-----+---------+---------
A | t | f
Z | t | t
| t | f
뿐만 아니라 있습니다 null
은 “배열”에서뿐만 아니라 null
에서이 z
이런 식으로 비교되고있다.
답변
문법 문제로 보았을 때 행과 배열 비교ANY
에서 다음과 같이 정의됩니다 .
식 연산자 ANY (배열 식)
그러나 is distinct from
연산자는 아니지만 비교 연산자 에서 알 수 있듯이 “구문”입니다 .
이 동작이 적합하지 않은 경우 IS [NOT] DISTINCT FROM
구문을 사용하십시오.
PostgreSQL에는 사용자 정의 연산자가 있으므로 다음과 같은 목적으로 연산자 / 함수 콤보를 정의 할 수 있습니다.
create function is_distinct_from(text, text) returns bool as
'select $1 is distinct from $2;' language sql;
create operator <!> (
procedure=is_distinct_from(text,text),
leftarg=text, rightarg=text
);
그런 다음 앞에 올 수 있습니다 ANY
.
select count(*)
from (select 'A' foo union all select 'Z' union all select null) z
where foo <!> any(array[null, 'A']);
카운트 ------- 삼 (1 행)
답변
운영자
이것은 @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[]
) 의 배열 의 경우 결과는 항상 참입니다. 그게 의도입니까? “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
.. 하나 이상의 요소가 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
솔루션 보다 조금 더 장황 하지만 실질적으로 더 빠릅니다.