2013-01-28 83 views
15

यहाँ मेरी क्वेरीORA-01,799: एक सबक्वेरी करने वाली में शामिल हो गए बाहरी एक स्तंभ नहीं हो सकता है

SELECT 
    COUNT(C.SETID) 
FROM 
    MYCUSTOMER C 
    LEFT OUTER JOIN MYCUSTOPTION CO 
    ON 
     (C.SETID = CO.SETID 
      AND C.CUST_ID = CO.CUST_ID 
      AND CO.effdt = ( 
       SELECT MAX(COI.EFFDT) 
       FROM MYCUSTOPTION COI 
       WHERE 
        COI.SETID = CO.SETID 
            AND COI.CUST_ID = CO.CUST_ID 
            AND COI.EFFDT <=SYSDATE  
       ) 
    ) 

है और यहाँ है कि मैं त्रुटि संदेश आ रहा है ..

enter image description here

मैं क्या गलत कर रहा हूं???

+0

कैंपस समाधान? Yukk! –

उत्तर

26

आप उप क्वेरी धक्का द्वारा कि पुनर्लेखन कर सकते हैं ताकि अपनी नहीं बाहरी में शामिल हो गए:

select Count(C.setid) 
    from mycustomer C 
     left outer join (select * 
          from mycustoption co 
         where co.effdt <= (select Max(COI.effdt) 
               from mycustoption COI 
              where COI.setid = co.setid 
               and COI.cust_id = co.cust_id 
               and COI.effdt <= sysdate)) co 
        on (C.setid = CO.setid 
         and C.cust_id = CO.cust_id) 
+0

में बाहर ले लिया, मैंने आंतरिक चयन कथन के अंत में 'सह' को अनदेखा किया sysdate), आंतरिक चयन कथन की शुरुआत में इसे 'सह' के साथ भ्रमित कर रहा है। मेरी पूछताछ में, मैंने उस भ्रम से बचने के लिए, उन्हें अलग बना दिया। लेकिन, यह वही था जो मैं खोज रहा था। – thursdaysgeek

2

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

सवाल यह है कि, यह बिल्कुल क्यों है? आपके पास "< =" दो स्थानों में स्थितियां हैं, इसलिए भविष्यवाणी अनिवार्य रूप से कहती है "सभी रिकॉर्ड जिनकी प्रभावी तिथि नवीनतम प्रभावी तिथि से बाद में नहीं है जो अब बाद में नहीं है"। यदि यह आप वास्तव में क्या चाहते हैं, तो आप इसे आसान बनाने में कर सकता करने के लिए "सभी रिकॉर्ड जिसका प्रभावी तिथि के बाद नहीं अब से है", यानी .:

ON 
    (C.SETID = CO.SETID 
     AND C.CUST_ID = CO.CUST_ID 
     AND CO.effdt <= SYSDATE  
) 

देखा, कोई सबक्वेरी।

लेकिन क्या वास्तव में आप क्या चाहते हैं, या क्या आपका मतलब है कि पहले "< =" बस होना "=" - यानी अब हाल ही में प्रभावी तारीख के साथ रिकॉर्ड मिल गया है? यदि आप वास्तव में चाहते हैं, तो यह फिर से लिखना अधिक जटिल होगा।

+0

हमें उस रिकॉर्ड को लेने की आवश्यकता है जो उस cust_id के लिए MYCUSTOPTION में सबसे हालिया है ... –

+0

ने क्वेरी को अपडेट किया और <= पहले बाहरी खंड –

1

आपका प्रश्न पहले से ही उत्तर दिया गया है, लेकिन किसी को एक अलग मामला हो सकता है, जहां वे नवीनतम EFFDT प्राप्त करने की आवश्यकता एक निश्चित तिथि के बजाय, एक कॉलम के आधार पर। उन मामलों के लिए, मैं केवल एक अपूणर् विकल्प है, और एक बदसूरत समाधान ... पाया

अपूर्ण विकल्प:

SELECT ... 
FROM MYTABLE N, CUST_OPT C 
WHERE etc... 
AND C.SETID   (+) = N.SETID 
AND C.CUST_ID   (+) = N.CUST_ID 
AND NVL(C.EFFDT,TO_DATE('01011900','DDMMYYYY')) = NVL((SELECT MAX(EFFDT) 
                 FROM CUST_OPT SC 
                 WHERE SC.SETID = C.SETID 
                 AND SC.CUST_ID = C.CUST_ID 
                 AND SC.EFFDT <= N.ISSUE_DT) 
                 ,TO_DATE('01011900','DDMMYYYY')) 

यह एक अपूर्ण विकल्प है क्योंकि अगर CUST_OPT तालिका भविष्य दिनांकों है, लेकिन कोई वर्तमान (< = N.ISSUE_DT) तिथियां, बाहरी जुड़ाव काम नहीं करेगा और कोई पंक्तियां वापस नहीं की जाएंगी। आम तौर पर पीपुल्स सॉफ्ट शब्द (हाँ मैंने आपके सेटिड + ईएफएफडीटी को देखा है! ;- डी) यह अक्सर ऐसा नहीं होता क्योंकि लोग "हमेशा के लिए" से पहले मूल्य को प्रभावी बनाने के लिए 01/01/1900 ईएफएफडीटी बनाते हैं, लेकिन तब से यह हमेशा मामला नहीं है;

SELECT n.field1, n.field2, 
     CASE WHEN NVL(c.EFFDT,n.ISSUE_DT-1)<=n.ISSUE_DT THEN c.field1 ELSE NULL END, 
     CASE WHEN NVL(c.EFFDT,n.ISSUE_DT-1)<=n.ISSUE_DT THEN c.field2 ELSE NULL END 
FROM MYTABLE N, CUST_OPT C 
WHERE etc... 
AND C.SETID   (+) = N.SETID 
AND C.CUST_ID   (+) = N.CUST_ID 
AND NVL(C.EFFDT,TO_DATE('01011900','DDMMYYYY')) = NVL((SELECT MAX(EFFDT) 
                 FROM CUST_OPT SC 
                 WHERE SC.SETID = C.SETID 
                 AND SC.CUST_ID = C.CUST_ID 
                 AND SC.EFFDT <= N.ISSUE_DT) 
                ,NVL((SELECT MIN(EFFDT) 
                  FROM CUST_OPT SC 
                  WHERE SC.SETID = C.SETID 
                  AND SC.CUST_ID = C.CUST_ID 
                  AND SC.EFFDT >= N.ISSUE_DT) 
                 ,TO_DATE('01011900','DDMMYYYY') 
                 ) 
                ) 

यह: जो इस है

मैं भी एक बदसूरत विकल्प पाया (लेकिन मैं वास्तव में यह सलाह देते हैं, और यह समस्या का हल है, तो यह एक समाधान कॉल),: हम भी एक बदसूरत समाधान है विकल्प भविष्य की पंक्तियों को वापस कर देगा जिन्हें अनदेखा किया जाना चाहिए! इसलिए हम SELECT स्टेटमेंट पर स्थितियां जोड़ते हैं जो वापस किए गए मानों को इंगित करेंगे, अगर वे पुनर्प्राप्त करने के लिए नहीं थे। जैसा मैंने कहा था ... यह एक यूजीली समाधान है, लेकिन यह एक समाधान है।

मेरे बदसूरत समाधान के लिए, यदि पंक्तियों को बाद में एक एप्लीकेशन इंजन या पीएल/एसक्यूएल या जो कुछ भी संसाधित किया जाएगा; आप प्रत्येक कॉलम के लिए केस स्टेटमेंट रखने के बजाय, केवल एक नया कॉलम जोड़ सकते हैं जो आपको बताएगा कि आपने "अनुचित" डेटा प्राप्त किया है और इस कॉलम के आधार पर बाद में अपने कोड में फ़ील्ड को अनदेखा कर दिया है, जैसे:

CASE WHEN NVL(c.EFFDT,n.ISSUE_DT-1)<=n.ISSUE_DT THEN 'N' ELSE 'Y' END AS IGNORE_CUST_OP_COLS