2011-11-16 11 views
40

पर पास सरणी को MySQL संग्रहीत दिनचर्या में पैरामीटर के रूप में तारों की एक सरणी पारित करने की आवश्यकता है। सरणी लंबी हो सकती है और इसके तत्वों की संख्या तय नहीं होती है। मैं फिर स्ट्रिंग मान को एक कॉलम के साथ एक इन-मेमोरी टेबल में रखना चाहता हूं, इसलिए मैं डेटा के साथ काम कर सकता हूं। मुझे नहीं पता कि यह MySQL में किया जा सकता है या नहीं। शायद गंदा कामकाज की जरूरत है।MySQL संग्रहीत दिनचर्या

उदाहरण के लिए, मैं तार केले, एप्पल, और ऑरेंज है। अब मैं इन फलों पर अपने MySQL Fruits तालिका से डेटा प्राप्त करना चाहता हूं। छद्म कोड:

create function GetFruits(Array fruitArray) 
    declare @temp table as 
     fruitName varchar(100) 
    end 

    @temp = convert fruitArray to table 
    select * from Fruits where Name in (select fruitName from @temp) 
end 

Microsoft SQL सर्वर आप TEXT डेटाप्रकार का उपयोग करें और एक XML स्ट्रिंग के रूप में सरणी सबमिट करते हैं, तेजी से में स्मृति तालिका बनाने के लिए अनुमति देता है। हालांकि, मुझे नहीं लगता कि तकनीक MySQL में संभव है।

यह करने के तरीके पर कोई मदद की सराहना की जाएगी!

उत्तर

55

आप अपनी सूची के साथ एक स्ट्रिंग पास कर सकते हैं और एक क्वेरी चलाने के लिए prepared statements का उपयोग कर सकते हैं, उदा। -

DELIMITER $$ 

CREATE PROCEDURE GetFruits(IN fruitArray VARCHAR(255)) 
BEGIN 

    SET @sql = CONCAT('SELECT * FROM Fruits WHERE Name IN (', fruitArray, ')'); 
    PREPARE stmt FROM @sql; 
    EXECUTE stmt; 
    DEALLOCATE PREPARE stmt; 

END 
$$ 

DELIMITER ; 

उपयोग कैसे करें:

SET @fruitArray = '\'apple\',\'banana\''; 
CALL GetFruits(@fruitArray); 
+18

इस विधि एसक्यूएल इंजेक्शन हमले के लिए अतिसंवेदनशील होगा? – pixelfreak

+1

मुझे लगता है कि यह सरल INSERT, SELECT या आदि कमांड निष्पादित करने जैसा ही है। – Devart

+2

यह हैकी है। मैं एक अस्थायी तालिका के साथ शामिल होने का उपयोग करने के लिए कहूंगा। – bobobobo

2

मैं मेरी समस्या के लिए एक अजीब लेकिन कार्यात्मक समाधान के साथ आ गए हैं। यह एक आयामी सरणी के लिए काम करता है (अधिक आयाम मुश्किल हो जाएगा) और इनपुट है कि एक varchar में फिट बैठता है:

declare pos int;   -- Keeping track of the next item's position 
    declare item varchar(100); -- A single item of the input 
    declare breaker int;  -- Safeguard for while loop 

    -- The string must end with the delimiter 
    if right(inputString, 1) <> '|' then 
    set inputString = concat(inputString, '|'); 
    end if; 

    DROP TABLE IF EXISTS MyTemporaryTable; 
    CREATE TEMPORARY TABLE MyTemporaryTable (columnName varchar(100)); 
    set breaker = 0; 

    while (breaker < 2000) && (length(inputString) > 1) do 
    -- Iterate looking for the delimiter, add rows to temporary table. 
    set breaker = breaker + 1; 
    set pos = INSTR(inputString, '|'); 
    set item = LEFT(inputString, pos - 1); 
    set inputString = substring(inputString, pos + 1); 
    insert into MyTemporaryTable values(item); 
    end while; 

उदाहरण के लिए, इस कोड के लिए इनपुट स्ट्रिंग Apple|Banana|Orange हो सकता है। MyTemporaryTable स्ट्रिंग्स Apple, Banana, और Orange क्रमशः तीन पंक्तियों के साथ पॉप्युलेट किया जाएगा।

मैंने सोचा था कि स्ट्रिंग हैंडलिंग की धीमी गति इस दृष्टिकोण को बेकार प्रदान करेगी, लेकिन यह पर्याप्त तेज़ था (केवल 1000 प्रविष्टियों सरणी के लिए एक सेकंड का अंश)।

उम्मीद है कि यह किसी की मदद करेगा।

+0

बहुत अधिक स्ट्रिंग हैकिंग! – bobobobo

19

बस उस तरह FIND_IN_SET का उपयोग करें:

mysql> SELECT FIND_IN_SET('b','a,b,c,d'); 
     -> 2 

तो आप कर सकते हैं:

select * from Fruits where FIND_IN_SET(fruit, fruitArray) > 0 
+1

केवल नकारात्मक पक्ष यह है कि यह संग्रहित प्रक्रिया विकल्प से धीमा है – kellogs

+1

@ केलॉग्स - आपका क्या मतलब है? आप इसे संग्रहीत प्रक्रिया में डाल सकते हैं –

+0

मैं अस्पष्ट था, क्षमा करें। यह एसपी बनाम गैर-एसपी के बारे में नहीं है, लेकिन इसके बारे में FIND_IN_SET बनाम कहां है। पहली विधि एक विजेता है, चाहे एसपी में हों या नहीं। – kellogs

1

यह एक चरित्र सरणी simulates लेकिन आप substr स्थानापन्न कर सकते हैं ईएलटी एक स्ट्रिंग सरणी अनुकरण के लिए

declare t_tipos varchar(255) default 'ABCDE'; 
declare t_actual char(1); 
declare t_indice integer default 1; 
while t_indice<length(t_tipos)+1 do 
    set t_actual=SUBSTR(t_tipos,t_indice,1); 
     select t_actual; 
     set t_indice=t_indice+1; 
end while; 
+0

'ईएलटी()' समारोह के बारे में पता नहीं था। लेकिन आप इस मामले में 't_tipos'' तारों चर के "सरणी" की घोषणा कैसे करते हैं? केले, ऐप्पल, ऑरेंज तीन तारों को कैसे निर्दिष्ट करें? – Gruber

9

अस्थायी तालिका के साथ शामिल होने का उपयोग करें। आपको फ़ंक्शंस, they are global पर अस्थायी तालिकाओं को पारित करने की आवश्यकता नहीं है।

create temporary table ids(id int) ; 
insert into ids values (1),(2),(3) ; 

delimiter // 
drop procedure if exists tsel // 
create procedure tsel() -- uses temporary table named ids. no params 
READS SQL DATA 
BEGIN 
    -- use the temporary table `ids` in the SELECT statement or 
    -- whatever query you have 
    select * from Users INNER JOIN ids on userId=ids.id ; 
END // 
DELIMITER ; 

CALL tsel() ; -- call the procedure 
3

आप यहाँ अस्थायी तालिकाओं का उपयोग करने के लिए नहीं करना चाहते हैं समारोह की तरह एक विभाजन स्ट्रिंग आप

SET @Array = 'one,two,three,four'; 
SET @ArrayIndex = 2; 
SELECT CASE 
    WHEN @Array REGEXP CONCAT('((,).*){',@ArrayIndex,'}') 
    THEN SUBSTRING_INDEX(SUBSTRING_INDEX(@Array,',',@ArrayIndex+1),',',-1) 
    ELSE NULL 
END AS Result; 
उपयोग कर सकते हैं
  • SUBSTRING_INDEX(string, delim, n) रिटर्न पहले n
  • SUBSTRING_INDEX(string, delim, -1) रिटर्न पिछले है केवल
  • REGEXP '((delim).*){n}' चेक करता है कि क्या कोई डिलीमीटर (यानी आप सीमा में हैं)
7

यह मदद करता है मुझे हालत आशा में करने के लिए इस मदद मिलेगी ..

CREATE PROCEDURE `test`(IN Array_String VARCHAR(100)) 
BEGIN 
    SELECT * FROM Table_Name 
    WHERE FIND_IN_SET(field_name_to_search, Array_String); 

END//; 

कॉलिंग:

call test('3,2,1');