2012-06-12 17 views
6

मैं एक संग्रहीत प्रक्रिया है कि एक से अधिक पैरामीटर (यानी pName, pHeight, pTeam) स्वीकार करता हैबाध्यकारी पैरामीटर

मैं क्वेरी इस तरह का निर्माण किया है:

SQLQuery VARCHAR2(6000); 
TestCursor T_CURSOR; 

SQLQuery := 'SELECT ID, Name, Height, Team FROM MyTable WHERE ID IS NOT NULL '; 


-- Build the query based on the parameters passed. 
IF pName IS NOT NULL 
    SQLQuery := SQLQuery || 'AND Name LIKE :pName '; 
END IF; 

IF pHeight IS > 0 
    SQLQuery := SQLQuery || 'AND Height = :pHeight '; 
END IF; 

IF pTeam IS NOT NULL 
    SQLQuery := SQLQuery || 'AND Team LIKE :pTeam '; 
END IF; 


OPEN TestCursor FOR SQLQuery USING pName, pHeight, pTeam; 

मैं निष्पादित हैं सभी मानकों को पार करने की प्रक्रिया, यह ठीक से चलता है।

लेकिन अगर मैं केवल एक या, मापदंडों के दो तो प्रक्रिया त्रुटियों बेहोश हो गए:

ORA-01006: bind variable does not exist 

मैं चुनिंदा जहां पैरामीटर मान इस्तेमाल किया गया था के आधार पर मानकों के साथ चर बाध्य करते हैं?

OPEN TestCursor FOR SQLQuery USING pName; 

या अगर दोनों pName और pTeam पारित किया गया था, तो:

OPEN TestCursor FOR SQLQuery USING pName, pTeam; 

आशा किसी को अधिक तरीकों शेड कर सकते हैं हल करने के लिए उदाहरण के लिए, अगर केवल pName पारित किया गया था, तो मैं केवल क्वेरी निष्पादित होगा इस। धन्यवाद।

संपादित करें: मैं वास्तव में निम्नलिखित इस्तेमाल कर सकते हैं:

- मापदंडों के आधार पर पारित कर दिया क्वेरी बनाएँ। यदि पीएनएएम पूर्ण नहीं है SQLQuery: = SQLQuery || 'और नाम पसंद' '' || पीएनएएम || '' ''; अंत IF;

IF pHeight IS > 0 
    SQLQuery := SQLQuery || 'AND Height = pHeight '; 
END IF; 

IF pTeam IS NOT NULL 
    SQLQuery := SQLQuery || 'AND Team LIKE ''' || pTeam || ''' '; 
END IF; 


OPEN TestCursor FOR SQLQuery; 

लेकिन यह बहुत SQL इंजेक्शन से कमजोर पड़ जाती ...

उत्तर

6

यह बेहद सुरुचिपूर्ण नहीं है बल्कि यह मतलब होगा कि आप हमेशा सभी तीन बाँध चर आपूर्ति कर सकता है, भले ही उनमें से कुछ अशक्त हैं। यदि आवश्यक हो तो आप केवल अतिरिक्त WHERE क्लॉज जोड़ते हैं।

(मैंने इसे अधिक पठनीय बनाने के लिए गतिशील एसक्यूएल को प्रारूपित करने का प्रयास किया है, तो आप इसे केवल एक लंबी स्ट्रिंग के रूप में आपूर्ति कर सकते हैं)।

FUNCTION myFunc (
    pName IN VARCHAR2, 
    pHeight IN VARCHAR2, 
    pTeam IN VARCHAR2 
) 
    RETURN T_CURSOR 
IS 
    -- Local Variables 
    SQLQuery VARCHAR2(6000); 
    TestCursor T_CURSOR; 
BEGIN 
    -- Build SQL query 
    SQLQuery := 'WITH t_binds '|| 
       ' AS (SELECT :v_name AS bv_name, '|| 
          ' :v_height AS bv_height, '|| 
          ' :v_team AS bv_team '|| 
         ' FROM dual) '|| 
       ' SELECT id, '|| 
         ' name, '|| 
         ' height, '|| 
         ' team '|| 
       ' FROM MyTable, '|| 
         ' t_binds '|| 
       ' WHERE id IS NOT NULL'; 

    -- Build the query WHERE clause based on the parameters passed. 
    IF pName IS NOT NULL 
    THEN 
    SQLQuery := SQLQuery || ' AND Name LIKE bv_name '; 
    END IF; 

    IF pHeight > 0 
    THEN 
    SQLQuery := SQLQuery || ' AND Height = bv_height '; 
    END IF; 

    IF pTeam IS NOT NULL 
    THEN 
    SQLQuery := SQLQuery || ' AND Team LIKE bv_team '; 
    END IF; 

    OPEN TestCursor 
    FOR SQLQuery 
    USING pName, 
     pHeight, 
     pTeam; 

    -- Return the cursor 
    RETURN TestCursor; 
END myFunc; 

मैं डीबी उपयोग के साथ एक कार्य केंद्र के सामने नहीं कर रहा हूँ तो मैं समारोह परीक्षण नहीं कर सकते, लेकिन यह करीब होना चाहिए (कृपया किसी भी वाक्यविन्यास त्रुटियों को क्षमा कर, यह एक लंबा दिन हो गया है!)

उम्मीद है कि यह मदद करता है ...

+0

t_binds कहां घोषित किया गया था? या मुझे इसे कहीं घोषित करने की ज़रूरत है? – Batuta

+0

यह एसक्यूएल कथन में 'इन' खंड में घोषित किया गया है, यह बाध्य चर को पकड़ने के लिए एक डमी टेबल है। यहां देखें: http://www.orafaq.com/node/1879 – Ollie

+0

यह कोशिश की लेकिन अभी भी ओआरए -01008 कहता है: – Batuta

7

आप DBMS_SQL पैकेज का उपयोग कर सकते हैं। यह गतिशील एसक्यूएल चलाने के लिए एक वैकल्पिक तरीका प्रदान करता है। यह संभवतया उपयोग करने के लिए थोड़ा अधिक बोझिल है, लेकिन यह अधिक लचीला हो सकता है, खासतौर पर बाध्य मानकों की अलग-अलग संख्या के साथ।

यहाँ कैसे आप इसे इस्तेमाल कर सकते हैं है (चेतावनी: मैं इस परीक्षण नहीं किया):

FUNCTION player_search (
    pName  IN VARCHAR2, 
    pHeight  IN NUMBER, 
    pTeam  IN VARCHAR2 
) RETURN SYS_REFCURSOR 
IS 
    cursor_name INTEGER; 
    ignore  INTEGER; 
    id_var  MyTable.ID%TYPE; 
    name_var  MyTable.Name%TYPE; 
    height_var MyTable.Height%TYPE; 
    team_var  MyTable.Team%TYPE; 
BEGIN 
    -- Put together SQLQuery here... 

    -- Open the cursor and parse the query   
    cursor_name := DBMS_SQL.OPEN_CURSOR; 
    DBMS_SQL.PARSE(cursor_name, SQLQuery, DBMS_SQL.NATIVE); 

    -- Define the columns that the query returns. 
    -- (The last number for columns 2 and 4 is the size of the 
    -- VARCHAR2 columns. Feel free to change them.) 
    DBMS_SQL.DEFINE_COLUMN(cursor_name, 1, id_var); 
    DBMS_SQL.DEFINE_COLUMN(cursor_name, 2, name_var, 30); 
    DBMS_SQL.DEFINE_COLUMN(cursor_name, 3, height_var); 
    DBMS_SQL.DEFINE_COLUMN(cursor_name, 4, team_var, 30); 

    -- Add bind variables depending on whether they were added to 
    -- the query. 
    IF pName IS NOT NULL THEN 
    DBMS_SQL.BIND_VARIABLE(cursor_name, ':pName', pName); 
    END IF; 

    IF pHeight > 0 THEN 
    DBMS_SQL.BIND_VARIABLE(cursor_name, ':pHeight', pHeight); 
    END IF; 

    IF pTeam IS NOT NULL THEN 
    DBMS_SQL.BIND_VARIABLE(cursor_name, ':pTeam', pTeam); 
    END IF; 

    -- Run the query. 
    -- (The return value of DBMS_SQL.EXECUTE for SELECT queries is undefined, 
    -- so we must ignore it.) 
    ignore := DBMS_SQL.EXECUTE(cursor_name); 

    -- Convert the DBMS_SQL cursor into a PL/SQL REF CURSOR. 
    RETURN DBMS_SQL.TO_REFCURSOR(cursor_name); 

EXCEPTION 
    WHEN OTHERS THEN 
    -- Ensure that the cursor is closed. 
    IF DBMS_SQL.IS_OPEN(cursor_name) THEN 
     DBMS_SQL.CLOSE_CURSOR(cursor_name); 
    END IF; 
    RAISE; 
END; 

(ध्यान दें:। DBMS_SQL.TO_REFCURSOR ओरेकल 11g में नया है)

+0

+1, मुझे डीबीएमएस_SQL का उपयोग करना पसंद है क्योंकि यह अधिक "समर्थित" है लेकिन मैंने सुझाई गई विधि से थोड़ा अधिक शामिल किया है। – Ollie

0

कैसे के बारे में

SQLQuery := 'SELECT ID, Name, Height, Team FROM MyTable WHERE ID IS NOT NULL '; 

SQLQuery := SQLQuery || 'AND Name LIKE :pName '; 
SQLQuery := SQLQuery || 'AND Team LIKE :pTeam '; 
SQLQuery := SQLQuery || 'AND (Height = :pHeight OR :pHeight = 0)'; 

OPEN TestCursor FOR SQLQuery USING nvl(pName, '%'), nvl(pTeam, '%'), nvl(pHeight, 0), nvl(pHeight, 0); 

?

+0

जैसे '%' शून्य को प्रभावित नहीं करता है। इसलिए यदि इनमें से कुछ फ़ील्ड शून्य हैं, तो आप झूठे होंगे –

1

मैं जिस दृष्टिकोण का उपयोग करता हूं वह है गतिशील एसक्यूएल में एक ईएलएसई मामले में राज्यों को आईएफ के विपरीत के रूप में शामिल करना है। आपका कोड परीक्षण करता है कि pName शून्य नहीं है, इसलिए मैं उत्पन्न क्वेरी परीक्षण में एक खंड जोड़ूंगा जो pName IS Null है। इस तरह आप क्वेरी के परिणामों को प्रभावित किए बिना हर बार एक ही पैरामीटर पास कर सकते हैं।

SQLQuery VARCHAR2(6000); 
TestCursor T_CURSOR; 

SQLQuery := 'SELECT ID, Name, Height, Team FROM MyTable WHERE ID IS NOT NULL '; 


-- Build the query based on the parameters passed. 
IF pName IS NOT NULL 
    SQLQuery := SQLQuery || 'AND Name LIKE :pName '; 
ELSE 
    SQLQuery := SQLQuery || 'AND :pName IS NULL'; 
END IF; 

IF pHeight IS > 0 
    SQLQuery := SQLQuery || 'AND Height = :pHeight '; 
ELSE 
    SQLQuery := SQLQuery || 'AND :pHeight <=0 '; 
END IF; 

IF pTeam IS NOT NULL 
    SQLQuery := SQLQuery || 'AND Team LIKE :pTeam '; 
ELSE 
    SQLQuery := SQLQuery || 'AND :pTeam IS NULL'; 
END IF; 


OPEN TestCursor FOR SQLQuery USING pName, pHeight, pTeam;