2011-08-12 13 views
7

मैं ओरेकल एपेक्स में एक एप्लीकेशन विकसित कर रहा हूं। मैं प्रयोक्ता आईडी के साथ एक स्ट्रिंग है कि अल्पविराम deliminated जो इस तरह दिखता है,पीएल/एसक्यूएल क्वेरी कॉमा डिलीमिनेटेड स्ट्रिंग

45,4932,20,19 

इस स्ट्रिंग

:P5_USER_ID_LIST 

के रूप में मैं एक प्रश्न है कि सभी उपयोगकर्ताओं है कि इस सूची के भीतर हैं मिलेगा चाहते संग्रहीत किया जाता है है मेरी क्वेरी इस तरह दिखती है

SELECT * FROM users u WHERE u.user_id IN (:P5_USER_ID_LIST); 

मुझे ओरेकल त्रुटि मिल रही है: अमान्य संख्या। अगर मैं क्वेरी में स्ट्रिंग को कड़ी मेहनत करता हूं तो यह काम करता है। इस तरह:

SELECT * FROM users u WHERE u.user_id IN (45,4932,20,19); 

कोई भी जानता है कि यह एक मुद्दा क्यों हो सकता है?

उत्तर

-1

आपको इसे गतिशील एसक्यूएल के रूप में चलाने की आवश्यकता होगी।

संपूर्ण स्ट्रिंग बनाएं, फिर इसे गतिशील रूप से चलाएं।

SELECT * FROM users u 
WHERE instr(',' || :P5_USER_ID_LIST ||',' ,',' || u.user_id|| ',', 1) !=0; 

चाल:

+1

ऐसा न करें - सबसे पहले यदि क्वेरी कई उपयोगकर्ता_आईडी के लिए अक्सर चलती है तो यह साझा पूल को कई अनुपयोगी कर्सर के साथ बाढ़ देगा और जल्दी से पूरे डीबी को एक कठिन पार्सिंग समस्या होगी। यदि आप बहुत सावधान नहीं हैं तो SQL इंजेक्शन का एक महत्वपूर्ण जोखिम भी है। –

2

एक आसान समाधान instr उपयोग करने के लिए है का उपयोग करने से एक देशी क्वेरी बनाएं

',' || :P5_USER_ID_LIST ||',' 

अपने स्ट्रिंग बनाने के लिए ,45,4932,20,19,

',' || u.user_id|| ',' 

अर्थात ,32, है और 32,4932,

9

एक बाँध चर बांधता एक मूल्य में स्ट्रिंग '45, 4932,20,19 किया जा रहा है, इस मामले में चुनने के लिए 'से बचने के लिए। आप रेन्डी द्वारा सुझाए गए गतिशील एसक्यूएल और कॉन्सटेनेशन का उपयोग कर सकते हैं, लेकिन आपको बहुत सावधान रहना होगा कि उपयोगकर्ता इस मान को संशोधित करने में सक्षम नहीं है, अन्यथा आपके पास SQL ​​इंजेक्शन समस्या है।

declare 
    array apex_application_global.vc_arr2; 
begin 
    array := apex_util.string_to_table (:P5_USER_ID_LIST, ','); 
    apex_collection.create_or_truncate_collection ('P5_ID_COLL'); 
    apex_collection.add_members ('P5_ID_COLL', array); 
end; 

तब करने के लिए आपकी क्वेरी को बदलने:

SELECT * FROM users u WHERE u.user_id IN 
(SELECT c001 FROM apex_collections 
WHERE collection_name = 'P5_ID_COLL') 
+0

'apex_collection.create_or_truncate_collection' मुझे 'NEXL (" APEX_040000 "।" WWV_FLOW_COLLECTIONS $ "में शामिल नहीं कर सकता है।" SESSION_ID ")' –

+0

@OleksandrPapchenko आप केवल एक एपेक्स सत्र के भीतर से' apex_collection' पैकेज को कॉल कर सकते हैं। –

0

कारण यह एक मुद्दा है

का अधिक सुरक्षित मार्ग एक PL/SQL प्रक्रिया में एक एपेक्स संग्रह में आईडी डाल करने के लिए किया जाएगा यह है कि आप केवल अपनी इच्छानुसार सूची में बाध्य नहीं कर सकते हैं, और केवल हर कोई इस गलती को कम से कम एक बार बनाता है क्योंकि वे ओरेकल (और शायद एसक्यूएल!) सीख रहे हैं।

जब आप स्ट्रिंग '32, 64,128 'बाँध, यह प्रभावी रूप से हो जाता है एक प्रश्न की तरह:

select ... 
from t 
where t.c1 in (32,64,128) 

पहला उदाहरण एक भी है:

select ... 
from t 
where t.c1 in ('32,64,128') 

ओरेकल करने के लिए यह करने के लिए पूरी तरह से अलग है सूची में स्ट्रिंग मान और दूसरी सूची में 3 संख्याएं हैं। अमान्य संख्या त्रुटि प्राप्त करने का कारण यह है कि ओरेकल स्ट्रिंग में '32, 64,128 'स्ट्रिंग को कास्ट करने का प्रयास करता है, जो स्ट्रिंग में अल्पविरामों के कारण नहीं कर सकता है।

हाल ही में हाल ही में कुछ बार "मैं सूची में कैसे बंधन करूं" प्रश्न का एक बदलाव आया है।

सामान्य रूप से, और किसी भी PLSQL का सहारा, SQL इंजेक्शन के बारे में चिंता या क्वेरी सही ढंग से बाध्यकारी नहीं के बिना, तो आप इस चाल का उपयोग कर सकते हैं:

with bound_inlist 
    as 
    (
    select 
    substr(txt, 
      instr (txt, ',', 1, level ) + 1, 
      instr (txt, ',', 1, level+1) - instr (txt, ',', 1, level) -1) 
      as token 
    from (select ','||:txt||',' txt from dual) 
    connect by level <= length(:txt)-length(replace(:txt,',',''))+1 
) 
    select * 
from bound_inlist a, users u 
where a.token = u.id; 
1

मैं इस स्थिति में कई बार सामना किया और यहाँ है मैं क्या 'है का उपयोग किया है:

SELECT * 
    FROM users u 
WHERE ','||to_char(:P5_USER_ID_LIST)||',' like '%,'||to_char(u.user_id)||',%' 

Ive की तरह ऑपरेटर थे, लेकिन आप एक पहलू यहाँ के एक छोटे से सावधान होना चाहिए: अपने मद P5_USER_ID_LIST होना चाहिए ", 45,4932,20,19," तो यह है कि जैसे एक साथ की तुलना करेंगे सटीक संख्या "', 45,'"।

जब यह इस तरह का उपयोग कर, चयन गलती कहेंगे नहीं देता: 5 से 15, 155 के साथ, 55

इसे आजमाएँ और मुझे पता है कि यह कैसे जाता है;)

चीयर्स, एलेक्स

+0

आप नहीं चाहते हैं या TO_CHAR के आसपास की आवश्यकता है: P5_USER_ID_LIST –

0

यदि संभव हो तो सीएसवी में अपने उपयोगकर्ता आईडी को स्टोर न करने का सबसे अच्छा विचार हो सकता है! उन्हें एक टेबल में रखें या एक सरणी आदि में असफल हो। आप एक सीएसवी फ़ील्ड को एक संख्या के रूप में बांध नहीं सकते हैं।

0

कृपया उपयोग न करें: कहां ',' || to_char (: P5_USER_ID_LIST) || ',' जैसे '%,' || to_char (u.user_id) || ',%' क्योंकि आप पूर्ण बल देंगे तालिका स्कैन हालांकि उपयोगकर्ता तालिका के साथ आपके पास बहुत से लोग नहीं हो सकते हैं इसलिए प्रभाव कम होगा लेकिन एंटरप्राइज़ वातावरण में अन्य तालिकाओं के विरुद्ध यह एक समस्या है।

संपादित करें: मैंने रेगेक्स विधि और वाइल्डकार्ड जैसे विधि के बीच अंतर प्रदर्शित करने के लिए एक स्क्रिप्ट एक साथ रखी है। न केवल रेगेक्स तेजी से है बल्कि यह भी बहुत मजबूत है।

-- Create table 
create table CSV_TEST 
(
    NUM NUMBER not null, 
    STR VARCHAR2(20) 
); 


create sequence csv_test_seq; 

begin 
    for j in 1..10 loop 
    for i in 1..500000 loop 
    insert into csv_test(num, str) values (csv_test_seq.nextval, to_char(csv_test_seq.nextval)); 
    end loop; 
    commit; 
    end loop; 
end; 
/

-- Create/Recreate primary, unique and foreign key constraints 
alter table CSV_TEST 
    add constraint CSV_TEST_PK primary key (NUM) 
    using index ; 
alter table CSV_TEST 
    add constraint CSV_TEST_FK unique (STR) 
    using index; 

select sysdate from dual; 
select * 
from csv_test t 
where t.num in (Select Regexp_Substr('100001, 100002, 100003 ,  100004, 100005','[^,]+', 1, Level) From Dual 
       Connect By Regexp_Substr('100001, 100002,100003, 100004, 100005', '[^,]+', 1, Level) Is Not Null); 
select sysdate from dual; 

select * 
from csv_test t 
where ('%,' || '100001,100002, 100003, 100004 ,100005' || ',%') like '%,' || num || ',%'; 
select sysdate from dual; 
select * 
from csv_test t 
where t.num in (Select Regexp_Substr('100001, 100002, 100003 ,  100004, 100005','[^,]+', 1, Level) From Dual 
       Connect By Regexp_Substr('100001, 100002,100003, 100004, 100005', '[^,]+', 1, Level) Is Not Null); 
select sysdate from dual; 

select * 
from csv_test t 
where ('%,' || '100001,100002, 100003, 100004 ,100005' || ',%') like '%,' || num || ',%'; 
select sysdate from dual; 

drop table csv_test; 
drop sequence csv_test_seq; 
0

टोनी एंड्रयूज से समाधान मेरे लिए काम करता है। प्रक्रिया को "पेज प्रोसेसिंग" >> "सबमिट करने के बाद" >> "प्रक्रियाओं" में जोड़ा जाना चाहिए।

संबंधित मुद्दे