sql - ओरेकल-तालिका उपनाम और नल मूल्यांकन में शामिल हों




oracle null (5)

संपादित करें : मैं नीचे कहना है कि वाक्यविन्यास अवैध है; आगे सोचा, कि मेरे हिस्से में बीएस है, मुझे नहीं पता है कि एक तथ्य के लिए (मैं इंगित नहीं कर सकता कि भाषा परिभाषा उपनामों में स्वयं को शामिल करने के लिए क्या आवश्यक है) मुझे अभी भी विश्वास है कि नीचे की व्याख्या संभवतः सही है, चाहे वह "बग" के लिए है या "अपरिभाषित व्यवहार" के लिए मैं नीचे उल्लिखित है

*

वाक्यविन्यास अवैध है (आप जानते थे - आप क्या देखना चाहते थे कि क्या होगा, और अगर आप आउटपुट को समझ सकते हैं)। मैं jarlh से सहमत हूं कि आपको एक त्रुटि संदेश प्राप्त हुआ होगा। स्पष्ट रूप से ओरेकल ने इस तरह से कोड नहीं किया

चूंकि यह मान्य वाक्यविन्यास नहीं है, इसलिए आप जो देख रहे हैं उसे बग नहीं कहा जा सकता (इसलिए मैं निक की टिप्पणी से असहमत हूं)। व्यवहार "अपरिभाषित" है - जब आप सिंटैक्स का उपयोग करते हैं जो ऑरेकल भाषा की परिभाषा के द्वारा समर्थित नहीं है, तो आप किसी भी प्रकार के पागल परिणाम प्राप्त कर सकते हैं, जिसके लिए ओरेकल कोई ज़िम्मेदारी नहीं ले रहा है

ठीक है, उस रास्ते से बाहर, क्या आप देख रहे हैं के लिए कोई स्पष्टीकरण है? मेरा मानना ​​है कि यह वास्तव में एक कार्टेशियन शामिल है, और नहीं एक संघ के रूप में निक ने सुझाव दिया

चलो खुद को अनुकूलक के जूते में डालते हैं यह एफओएम सूची में पहली तालिका को देखता है, यह स्कैन करता है, अब तक अच्छा है

फिर यह दूसरी तालिका पढ़ता है, और इसके पास कॉलम की एक सूची है:

tabNULL.val, tabNULL.descr, tabNULL.val, tabNULL.descr

tabNULL.val = tabNULL.val स्थिति में tabNULL.val = tabNULL.val

अनुकूलक मूर्ख है, यह स्मार्ट नहीं है यह आपके विपरीत नहीं है, इस बात पर एहसास नहीं है कि tabNULL का मतलब तालिका के दो अलग-अलग अवतारों के लिए खड़ा होना है। ऐसा लगता है कि समीकरण के दोनों ओर tabNULL.val समान मूल्य हैं और वे दोनों तालिका के पहले "अवतार" को देखें एकमात्र ऐसा मामला तब विफल हो जाता है, यदि tabNULL.val नल है, तो यह क्वेरी को tabNULL.val IS NOT NULL बनने के साथ क्वेरी को tabNULL.val IS NOT NULLtabNULL.val IS NOT NULL

tabNULL.val IS NOT NULL लिए केवल पहली तालिका की जांच की tabNULL.val IS NOT NULL ; ऑप्टिमाइज़र "पता" नहीं करता है tabNULL.val सूची में फिर से दिखाई देता है और इसका एक अलग अर्थ हो सकता है! तो शामिल होने होता है; इस बिंदु पर कोई अन्य शर्तें नहीं रहती हैं, इसलिए तालिका के दूसरे अवतार में दोनों पंक्तियों में शामिल होने के लिए पंक्तियों का उत्पादन होगा, A, ONE CHAR प्रथम तालिका से A, ONE CHAR

फिर, प्रक्षेपण में, फिर से केवल पहली बार tabNULL.val पढ़ा जाएगा और आउटपुट में दोनों कॉलम को आबाद करेगा। आप दो बार मूल्य tabNULL.val पर न लौटने के लिए क्वेरी इंजिन से पूछते हैं, और आपके दिमाग में यह अलग-अलग जगहों से है, लेकिन केवल एक स्मृति स्थान लेबल tabNULL.val , और यह पहले तालिका से आया था जो स्टोर करता है।

बेशक, बहुत कुछ जानते हैं कि अनुकूलक और क्वेरी इंजिन क्या कर रहे हैं, लेकिन यह निश्चित है कि इस मामले में मुझे लगता है कि यह एक बहुत ही सुरक्षित अनुमान है

मैं सिर्फ एक उदाहरण बनाने की कोशिश कर रहा था कि ओरेकल में NULL को 'अप्रत्याशित' व्यवहार करने के लिए कैसे प्रेरित किया जा सकता है, लेकिन मैंने ऐसा कुछ पाया जो मुझे उम्मीद नहीं थी ...

सेट अप:

create table tabNull (val varchar2(10), descr varchar2(100));
insert into tabNull values (null, 'NULL VALUE');
insert into tabNull values ('A', 'ONE CHAR');

यह मुझे जो उम्मीद थी, वह देता है:

SQL> select * from tabNull T1 inner join tabNull T2 using(val);

VAL        DESCR                DESCR
---------- -------------------- --------------------
A          ONE CHAR             ONE CHAR

यदि मैं तालिका उपनाम निकाल देता हूं, तो मुझे मिलती है:

SQL> select * from tabNull inner join tabNull using(val);

VAL        DESCR                DESCR
---------- -------------------- --------------------
A          ONE CHAR             ONE CHAR
A          ONE CHAR             ONE CHAR

और यह मेरे लिए काफी आश्चर्य की बात है

एक कारण दो प्रश्नों के निष्पादन योजना में पाया जा सकता है; तालिका एलियंस के साथ, ओरेकल एक T1.val = T2.val और फिर T1.val = T2.val लिए जांच करता है:

------------------------------------------------------------------------------
| Id  | Operation          | Name    | Rows  | Bytes | Cost (%CPU)| Time     |
------------------------------------------------------------------------------
|   0 | SELECT STATEMENT   |         |     1 |   118 |     7  (15)| 00:00:01 |
|*  1 |  HASH JOIN         |         |     1 |   118 |     7  (15)| 00:00:01 |
|   2 |   TABLE ACCESS FULL| TABNULL |     2 |   118 |     3   (0)| 00:00:01 |
|   3 |   TABLE ACCESS FULL| TABNULL |     2 |   118 |     3   (0)| 00:00:01 |
------------------------------------------------------------------------------

Predicate Information (identified by operation id):
---------------------------------------------------

   1 - access("T1"."VAL"="T2"."VAL")

उपनाम के बिना, यह पहले तालिका की एक घटना को नल मूल्यों के लिए फ़िल्टर करता है, इस प्रकार केवल एक पंक्ति को चुनता है, और फिर यह दूसरी घटना के साथ एक कार्टेशियन बनाता है, इस प्रकार दो पंक्तियां प्रदान करता है; भले ही यह सही है, मैं एक कार्टेशियन के नतीजे की अपेक्षा करता हूं, लेकिन मेरे पास कोई DESCR = 'NULL VALUE' के साथ कोई पंक्ति नहीं है

--------------------------------------------------------------------------------
| Id  | Operation            | Name    | Rows  | Bytes | Cost (%CPU)| Time     |
--------------------------------------------------------------------------------
|   0 | SELECT STATEMENT     |         |     2 |   118 |     6   (0)| 00:00:01 |
|   1 |  MERGE JOIN CARTESIAN|         |     2 |   118 |     6   (0)| 00:00:01 |
|*  2 |   TABLE ACCESS FULL  | TABNULL |     1 |    59 |     3   (0)| 00:00:01 |
|   3 |   BUFFER SORT        |         |     2 |       |     3   (0)| 00:00:01 |
|   4 |    TABLE ACCESS FULL | TABNULL |     2 |       |     3   (0)| 00:00:01 |
--------------------------------------------------------------------------------

Predicate Information (identified by operation id):
---------------------------------------------------

   2 - filter("TABNULL"."VAL" IS NOT NULL)

क्या यह किसी तरह सही / उम्मीद है? लौटे हुए पंक्तियों की संख्या की तुलना में कार्टेशियन के नतीजे का मूल्य भी अजनबी नहीं है? क्या मैं योजनाओं को गलत समझता हूं, या कुछ इतनी बड़ी लापता हूं जिसे मैं नहीं देख सकता हूं?


USING कीवर्ड मेरे लिए नया है, लेकिन मैंने जो पढ़ा है उसके अनुसार एसक्यूएल सम्मिलित वाक्यविन्यास सरल बनाने का एक नया तरीका है। (देखें ओरेकल उपयोग वाला कीवर्ड )

select * from tabNull T1 inner join tabNull T2 using(val);
के बराबर है:
select * from tabNull T1 inner join tabNull T2 on T1.val = T2.val;

select * from tabNull inner join tabNull using(val);
के बराबर है:
select * from tabNull inner join tabNull on tabNull.val = tabNull.val;

समस्या यह है कि दूसरी क्वेरी में शामिल होने वाले tabNull.val = tabNull.val में तालिका के नाम tabNull.val = tabNull.val अद्वितीय नहीं हैं।

यह खराब सिंटैक्स है, जिसके परिणामस्वरूप एक त्रुटि हो सकती है अगर पारंपरिक शामिल वाक्यविन्यास का उपयोग किया गया था।

मेरा सबसे अच्छा अनुमान है कि ओरेकल ने दो तालिकाओं (जो कि सभी पंक्तियों को दोगुनी हो) पर पूर्ण क्रॉस-उत्पाद का प्रदर्शन किया, और फिर अशक्तों को समाप्त कर दिया क्योंकि USING को equioins (यानी, बराबर " = ") का USING करना चाहिए और null कुछ के बराबर नहीं है ।


Http://docs.oracle.com/javadb/10.10.1.2/ref/rrefsqljusing.html के using(val) अनुसार यहां ON tabnull.val=tabnull.val रूप में अनुवाद किया जाता है

select tabNull.*, tabNull.descr from tabNull inner join tabNull 
on tabNull.val = tabNull.val;

एक योजना बनाने के बाद ओरेकल को [जोन] प्रत्येक जॉइन के सदस्य के लिए अलग-अलग एलियंस प्रदान करना चाहिए लेकिन SELECT और ON में किसी भी स्थान पर दूसरे उपनाम का उपयोग करने का कोई कारण नहीं है। इसलिए

select t1.*, t1.descr from tabNull t1 inner join tabNull t2 
on t1.val = t1.val;

योजना

--------------------------------------------------------------------------------                        
| Id  | Operation            | Name    | Rows  | Bytes | Cost (%CPU)| Time     |                        
--------------------------------------------------------------------------------                        
|   0 | SELECT STATEMENT     |         |     2 |    28 |     4   (0)| 00:00:01 |                        
|   1 |  MERGE JOIN CARTESIAN|         |     2 |    28 |     4   (0)| 00:00:01 |                        
|*  2 |   TABLE ACCESS FULL  | TABNULL |     1 |    14 |     2   (0)| 00:00:01 |                        
|   3 |   BUFFER SORT        |         |     2 |       |     2   (0)| 00:00:01 |                        
|   4 |    TABLE ACCESS FULL | TABNULL |     2 |       |     2   (0)| 00:00:01 |                        
--------------------------------------------------------------------------------                        


Predicate Information (identified by operation id):                                                     
---------------------------------------------------                                                     

   2 - filter("T1"."VAL" IS NOT NULL)    

क्षमा करें, मुझे नहीं लगता कि यह वाकई एक जवाब है। यह ज्यादातर आपके पोस्टिंग में केवल एक टिप्पणी / उत्तर है:

लौटे हुए पंक्तियों की संख्या की तुलना में कार्टेशियन के नतीजे का मूल्य भी अजनबी नहीं है?

किसी योजना के हर चरण में "प्रक्षेपण" होता है जो कि कॉलम / अभिव्यक्ति की सूची होती है जो चरण से आउटपुट होते हैं। क्या हो रहा है यह है कि समान उपनामों में ओरेकल के प्रक्षेपण के कारण गठबंधन किया जा सकता है कि केवल एक स्तंभ में दो कॉलम क्या होना चाहिए।

यह देखना आसान है कि क्या आप अपने उदाहरण में दो अलग-अलग तालिकाओं का उपयोग करते हैं और विशिष्ट नामित स्तंभों की एक जोड़ी जोड़ते हैं, यह देखने के लिए कि क्या हो रहा है:

create table tabNull1 (val varchar2(10), descr varchar2(100), t1_real_descr varchar2(100) );
insert into tabNull1 values (null, 'T1-NULL VALUE', 'T1-NULL VALUE');
insert into tabNull1 values ('A', 'T1-ONE CHAR', 'T1-ONE CHAR');


create table tabNull2 (val varchar2(10), descr varchar2(100), t2_real_descr varchar2(100) );
insert into tabNull2 values (null, 'T2-NULL VALUE', 'T2-NULL VALUE');
insert into tabNull2 values ('A', 'T2-ONE CHAR', 'T2-ONE CHAR');

select * from tabNull1 t inner join tabNull2 t using(val);

VAL    DESCR            T1_REAL_DESCR     DESCR_1       T2_REAL_DESCR                                                                                        
------ ---------------- ----------------- ------------- -----------------
A      T2-ONE CHAR      T1-NULL VALUE     T2-ONE CHAR   T2-ONE CHAR
A      T2-ONE CHAR      T1-ONE CHAR       T2-ONE CHAR   T2-ONE CHAR

जैसा कि आप देख सकते हैं, कार्टेशियन में शामिल होने के बारे में आपका सिद्धांत सही था।


"इनर जॉइन" और "बाहरी जॉइन" के बीच क्या अंतर है?

वे एसक्यूएल में सबसे अधिक इस्तेमाल किए जाने वाले अस्तित्व वाले ऑपरेटरों हैं, जहां INNER JOIN'अस्तित्व' के LEFT OUTER JOINलिए उपयोग किया जाता है और 'अस्तित्व में नहीं है' के लिए प्रयोग किया जाता है।

इन प्रश्नों पर विचार करें:

users who have posted and have votes
users who have posted but have no badges

जो लोग सेट-आधारित समाधान (एक उद्योग शब्द) की तलाश करते हैं, वे संबंधित प्रश्नों को इस प्रकार पहचानेंगे:

users who have posted INTERSECT users who have votes
users who have posted MINUS users who have badges

इन्हें मानक एसक्यूएल में अनुवाद करना:

SELECT UserId FROM Posts
INTERSECT 
SELECT UserId FROM Votes;

SELECT UserId FROM Posts
EXCEPT 
SELECT UserId FROM Badges;

अन्य सेट समावेशन के समान लाइनों के साथ सोचेंगे:

users who have posted and IN the set of users who have votes
users who have posted and NOT IN the set of users who have badges

इन्हें मानक एसक्यूएल में अनुवाद करना:

SELECT UserId 
  FROM Posts
 WHERE UserId IN ( SELECT UserId FROM Votes );

SELECT UserId 
  FROM Posts
 WHERE UserId NOT IN ( SELECT UserId FROM Badges );

कुछ सेटों के भीतर 'अस्तित्व' के संदर्भ में सोचेंगे

users who have posted and EXIST in the set of users who have votes
users who have posted and do NOT EXIST in the set of users who have badges

मानक SQL (ध्यान दें कि हम अब यानी सीमा चर का उपयोग करने की आवश्यकता है में इन का अनुवाद p, v, b):

SELECT p.UserId 
  FROM Posts p
 WHERE EXISTS ( SELECT *
                  FROM Votes v
                 WHERE v.UserId = p.UserId );

SELECT p.UserId 
  FROM Posts p
 WHERE NOT EXISTS ( SELECT *
                      FROM Badges b
                     WHERE b.UserId = p.UserId );

हालांकि, मैंने पाया है कि "उद्योग मानक" दृष्टिकोण विशेष रूप से जुड़ने का उपयोग करना है। मुझे नहीं पता कि सोच क्या है ( उपकरण का कानून ? समयपूर्व अनुकूलन ?), तो मैं सीधे वाक्यविन्यास पर जाऊंगा:

SELECT p.UserId 
  FROM Posts p
       INNER JOIN Votes v ON v.UserId = p.UserId;

SELECT p.UserId 
  FROM Posts p
       LEFT JOIN Badges b ON b.UserId = p.UserId
 WHERE b.UserId IS NULL;

ध्यान देने योग्य बातें:

  • केवल प्रक्षेपण से है Usersलेकिन हम अभी भी उन सभी रेंज चर (की जरूरत है p, v, b) खोज स्थितियों के लिए।
  • UserId IS NULLखोज हालत के लिए 'अंतर्गत आता है' OUTER JOINलेकिन क्वेरी में काट दिया गया है।
  • LEFTउद्योग मानक है: पेशेवरों का उपयोग करने से बचने के लिए एक प्रश्न फिर से लिखना होगा RIGHT!
  • OUTERतैयार किए गए कीवर्ड LEFT OUTER JOINछोड़ा गया है।

अंतिम शब्द:

कभी-कभी प्रश्नों का उपयोग केवल यह निर्धारित करने के लिए किया जाता है कि मूल्य मौजूद हैं या किसी अन्य सेट में मौजूद नहीं हैं। प्रक्षेपित किए गए विशेषताओं ( SELECTखंड में कॉलम ) पर ध्यान से देखना सीखें : यदि शामिल तालिका से कोई भी नहीं है तो उन्हें केवल अस्तित्व वाले ऑपरेटरों के रूप में उपयोग किया जा रहा है। इसके अतिरिक्त बाहरी शामिल होने के लिए, खंड <key_column> IS NULLमें उदाहरणों की तलाश करें WHERE





sql oracle null