2011-11-16 19 views
40

Tôi cần chuyển một chuỗi các chuỗi như tham số cho một thường trình được lưu trữ MySQL. Mảng có thể dài và số phần tử của nó không cố định. Sau đó tôi muốn đặt các giá trị chuỗi vào một bảng trong bộ nhớ với một cột, vì vậy tôi có thể làm việc với dữ liệu. Tôi không biết nếu điều này có thể được thực hiện trong MySQL. Có lẽ cách giải quyết dở dang là cần thiết.Vượt qua mảng tới thường trình được lưu trữ của MySQL

Ví dụ, tôi có chuỗi Banana, của Apple, và Orange. Bây giờ tôi muốn lấy dữ liệu về các loại trái cây này từ bảng MySQL Fruits của tôi. Pseudo code:

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 cho phép bạn sử dụng TEXT datatype và nộp mảng như một chuỗi XML, nhanh chóng tạo ra các bảng trong bộ nhớ. Tuy nhiên, tôi không nghĩ rằng kỹ thuật đó là có thể trong MySQL.

Bất kỳ trợ giúp nào về cách thực hiện việc này sẽ được đánh giá cao!

Trả lời

55

Bạn có thể chuyển một chuỗi với danh sách của mình và sử dụng prepared statements để chạy truy vấn, ví dụ: -

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 ; 

Làm thế nào để sử dụng:

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

có phương pháp này dễ bị tấn công SQL injection? – pixelfreak

+1

Tôi nghĩ nó giống như thực thi lệnh INSERT, SELECT hoặc vv đơn giản. – Devart

+2

Đó là hacky. Tôi muốn nói để sử dụng một tham gia với một bảng tạm thời. – bobobobo

2

Tôi đã đưa ra một giải pháp vụng về nhưng chức năng cho vấn đề của tôi. Nó làm việc cho một mảng một chiều (nhiều kích thước sẽ được khôn lanh) và đầu vào phù hợp với một 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; 

Ví dụ, đầu vào cho mã này có thể là chuỗi Apple|Banana|Orange. MyTemporaryTable sẽ được điền bằng ba hàng chứa các chuỗi Apple, BananaOrange tương ứng.

Tôi nghĩ tốc độ xử lý chuỗi chậm sẽ làm cho phương pháp này trở nên vô ích, nhưng nó đủ nhanh (chỉ một phần nhỏ của giây đối với mảng 1.000 mục).

Hy vọng điều này sẽ giúp ai đó.

+0

Hacking quá nhiều chuỗi! – bobobobo

19

Đơn giản chỉ cần sử dụng FIND_IN_SET như thế:

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

vì vậy bạn có thể làm:

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

nhược điểm duy nhất là nó là chậm hơn so với tùy chọn thủ tục lưu trữ – kellogs

+1

@kellogs - bạn có ý nghĩa gì? bạn có thể đặt nó trong thủ tục lưu trữ –

+0

Tôi đã không rõ ràng, xin lỗi. Đây không phải là về SP và không phải SP, nhưng về WHERE IN so với FIND_IN_SET. Phương pháp đầu tiên là một người chiến thắng, không có vấn đề nếu trong SP hay không. – kellogs

1

này mô phỏng một mảng nhân vật nhưng bạn có thể thay thế SUBSTR cho ELT để mô phỏng một mảng chuỗi

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

Không biết về hàm 'ELT()'. Nhưng làm thế nào để bạn khai báo "mảng" của biến chuỗi, trong trường hợp này 't_tipos'? Làm thế nào để xác định ba chuỗi chuối, táo, cam? – Gruber

9

Sử dụng kết hợp với bảng tạm thời. Bạn không cần phải chuyển các bảng tạm thời sang các hàm, 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

Nếu bạn không muốn sử dụng bảng tạm thời đây là một chuỗi phân chia như chức năng bạn có thể sử dụng

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) trả về n đầu tiên
  • SUBSTRING_INDEX(string, delim, -1) lợi nhuận cuối cùng chỉ
  • REGEXP '((delim).*){n}' kiểm tra xem có n dấu phân cách nào không (nghĩa là bạn đang ở trong giới hạn)
7

Điều này giúp cho tôi để làm trong tình trạng Hy vọng điều này sẽ giúp bạn ..

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'); 
Các vấn đề liên quan