क्या किसी से या सभी के साथ किसी भी तरह से जोड़ा जा सकता है?


13

संयोजन के एक postgres तरीका है 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']);
                                   ^

जवाबों:


7

शायद इस तरह :

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इस तरह से तुलना की जा रही है।


13

इसे व्याकरण की समस्या के रूप में देखते हुए, इसे ANY( रो और एरे तुलना में ) के रूप में परिभाषित किया गया है :

अभिव्यक्ति ऑपरेटर किसी भी (सरणी अभिव्यक्ति)

लेकिन is distinct fromएक ऑपरेटर नहीं है, यह एक "निर्माण" है जैसा कि हमें तुलना ऑपरेटरों में बताया गया है :

जब यह व्यवहार उपयुक्त नहीं है, तो निर्माणों से IS [NOT] DISTINCT F का उपयोग करें

चूंकि 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']);  
 गिनती 
-------
     3
(1 पंक्ति)

1
बहुत बढ़िया, आनंददायक जवाब।
एरविन ब्रान्डेसटेटर

यह निश्चित रूप से मेरे द्वारा सुझाए गए वर्कअराउंड से बहुत बेहतर है, खासकर @ इरविन के सुधार के साथ।
एंड्री एम

यह उत्तर और @ इरविन के सुझाए गए ट्वीक्स वास्तव में उत्कृष्ट हैं। मैं एंड्री को स्वीकार कर रहा हूं, लेकिन यह सिर्फ व्यक्तिगत पसंद का मामला है: मुझे यकीन है कि कई लोग आपकी सुंदरता को पसंद करेंगे।
जैक कहते हैं कि topanswers.xyz

@JackDouglas: मैंने मानक ऑपरेटरों के साथ एक वैकल्पिक समाधान जोड़ा।
एरविन ब्रान्डेसटेटर

यह दुर्भाग्यपूर्ण है ... सभी इरादों और उद्देश्यों के लिए, IS DISTINCT FROMएक ऑपरेटर नहीं होना चाहिए ? सिर्फ़ एक सिमेंटिक इश्यू के बजाय पार्सर की तकनीकी सीमा की तरह लगता है।
एंडी

10

ऑपरेटर

यह @ डैनियल के चतुर ऑपरेटर पर बन रहा है
इस पर रहते हुए, पॉलीमॉर्फिक प्रकारों का उपयोग करके फ़ंक्शन / ऑपरेटर कॉम्बो बनाएं । फिर यह किसी भी प्रकार के लिए काम करता है - निर्माण की तरह।
और फंक्शन करें 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
);

प्रतीकात्मक के साथ एक त्वरित खोज खाली आई, इसलिए ऑपरेटर <!>किसी भी मॉड्यूल में उपयोग में नहीं लगता है।

यदि आप इस ऑपरेटर का बहुत उपयोग करने जा रहे हैं, तो आप क्वेरी प्लानर की सहायता के लिए इसे कुछ और दे सकते हैं ( जैसे कि टिप्पणी में खोए हुए सुझाव )। शुरुआत के लिए, आप क्वेरी ऑप्टिमाइज़र की सहायता के लिए COMMUTATORऔर 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 .. यदि कम से कम एक तत्व है IS NULLऔर कोई तत्व नहीं है<> foo

तो, शेष कोने का मामला है जहां
- foo IS NULL
- और तत्वों test_arrके अलावा कुछ भी नहीं NULLहै।

यदि दोनों में से किसी एक को खारिज किया जा सकता है, तो हम किए जाते हैं। इसलिए, सरल परीक्षण का उपयोग करें यदि
- स्तंभ परिभाषित है NOT 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 में सभी NULLs सरणी है

फिर, यदि आप किसी ऐसे मूल्य के बारे में जानते हैं 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

यह एंड्री के EXCEPTसमाधान की तुलना में थोड़ा अधिक है , लेकिन यह काफी तेजी से है।


बनाते समय OPERATOR, COMMUTATOR(और NEGATOR, शायद उलटे IS NOT DISTINCT FROMऑपरेटर के साथ) क्लॉज की आपूर्ति की जानी चाहिए? postgresql.org/docs/current/static/xoper-optimization.html
14

1
@losthorse: मैंने इसे संबोधित करते हुए थोड़ा सा जोड़ा।
एरविन ब्रान्डेसटेटर

मैं इस ऑपरेटर का उपयोग इस तरह app_status (पूर्णांक) के आधार पर रिकॉर्ड को खत्म करने के लिए कर रहा हूं app_status <!> any(array[3,6])। दुर्भाग्य से, रिकॉर्ड पर इसका कोई प्रभाव नहीं पड़ता है। क्या यह पूर्णांक के साथ काम करता है?
एम। हबीब

@ एम। हबीब: कृपया अपना प्रश्न नए प्रश्न के रूप में पूछें । (सभी प्रासंगिक विवरणों के साथ!) आप संदर्भ के लिए इसे हमेशा लिंक कर सकते हैं - और वापस लिंक करने के लिए यहां एक टिप्पणी छोड़ दें।
इरविन ब्रान्डस्टेट्टर
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.