2011-11-16 9 views
40

Ho bisogno di passare una serie di stringhe come parametro ad una routine memorizzata MySQL. La matrice potrebbe essere lunga e il suo numero di elementi non è fisso. Poi voglio mettere i valori stringa in una tabella in memoria con una colonna, quindi posso lavorare con i dati. Non so se questo può essere fatto in MySQL. Forse sono necessari soluzioni sporche.Passare array alla routine memorizzata MySQL

Ad esempio, ho le stringhe Banana, Mela, e arancione. Ora voglio ottenere dati su questi frutti dalla mia tabella MySQL Fruits. pseudo codice:

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 Server consente di utilizzare il tipo di dati e presentare TEXT l'array come una stringa XML, rapidamente creando la tabella in memoria. Tuttavia, non penso che la tecnica sia possibile in MySQL.

Qualsiasi aiuto su come farlo sarebbe apprezzato!

risposta

55

È possibile passare una stringa con l'elenco e utilizzare uno prepared statements per eseguire una query, ad es. -

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 ; 

Come usare:

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

Sarebbe questo metodo essere suscettibile di attacco SQL injection? – pixelfreak

+1

Penso che sia lo stesso di eseguire comandi INSERT, SELECT o etc. – Devart

+2

Questo è hacky. Direi di usare un join con un tavolo temporaneo. – bobobobo

2

mi è venuta in mente una soluzione scomoda ma funzionale per il mio problema. Funziona per un array monodimensionale (più dimensioni sarebbe difficile) e l'ingresso che si inserisce in un 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; 

Ad esempio, ingresso per questo codice potrebbe essere la stringa Apple|Banana|Orange. MyTemporaryTable verrà popolato con tre righe contenenti le stringhe Apple, Banana e Orange rispettivamente.

Ho pensato che la bassa velocità di gestione delle stringhe renderebbe questo approccio inutile, ma è stato abbastanza veloce (solo una frazione di secondo per un array di 1000 voci).

Spero che questo aiuti qualcuno.

+0

Troppo hacking delle stringhe! – bobobobo

19

Basta usare FIND_IN_SET così:

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

modo da poter fare:

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

unico lato negativo è che è più lento dell'opzione di procedura memorizzata – kellogs

+1

@kellogs - cosa intendi? puoi metterlo nella stored procedure –

+0

Non ero chiaro, mi dispiace. Non si tratta di SP vs non SP, ma di WHERE IN vs FIND_IN_SET. Il primo metodo è un vincitore, non importa se in SP o meno. – kellogs

1

Questo simula un array di caratteri, ma si può sostituire SUBSTR per ELT per simulare un array di stringhe

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

Non conoscevo la funzione 'ELT()'. Ma come si dichiara la "matrice" delle stringhe variabili, in questo caso 't_tipos'? Come specificare le tre stringhe Banana, Apple, Orange? – Gruber

9

Utilizzare un join con una tabella temporanea. Non è necessario passare tabelle temporanee alle funzioni, 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

Se non si desidera utilizzare le tabelle temporanee: ecco uno stringa divisa come la funzione è possibile utilizzare

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) restituisce il primo n
  • SUBSTRING_INDEX(string, delim, -1) restituisce l'ultimo solo
  • REGEXP '((delim).*){n}' controlla se sono presenti n delimitatori (ovvero se ci sono dei limiti)
7

Ciò contribuisce per me fare in condizioni Spero che questo vi aiuterà a ..

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

END//; 

Calling:

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