Làm cách nào để mô phỏng một biến mảng trong MySQL?


91

vẻ như MySQL không có biến mảng. Tôi nên sử dụng gì để thay thế?


Dường như có hai lựa chọn thay thế được đề xuất: Một bảng vô hướng kiểu tập hợpbảng tạm thời . Câu hỏi tôi đã liên kết để gợi ý câu hỏi trước đây. Nhưng sử dụng các biến này thay vì các biến mảng có tốt không? Ngoài ra, nếu tôi đi với bộ, thì thành ngữ dựa trên bộ sẽ tương đương với điều foreachgì?


2
Sử dụng ELT.
Pacerier

1
@Pacerier: Bạn có thể liên kết đến một cuộc thảo luận dài hơn về ELT, có lẽ với một ví dụ dài hơn không?
einpoklum

Câu trả lời:


77

Tôi đang sử dụng các bảng tạm thời thay vì các biến mảng. Không phải là giải pháp tốt nhất, nhưng nó hoạt động.

Lưu ý rằng bạn không cần phải xác định chính thức các trường của chúng, chỉ cần tạo chúng bằng cách sử dụng SELECT:

CREATE TEMPORARY TABLE IF NOT EXISTS my_temp_table
SELECT first_name FROM people WHERE last_name = 'Smith';

(Xem thêm Tạo bảng tạm thời từ câu lệnh chọn mà không cần sử dụng Tạo bảng .)


1
Ohhh: o Tôi không biết SQL có cái này !! Các bảng chỉ tồn tại trong phạm vi các truy vấn al đang được chạy. KHÉO LÉO!
iGbanam

2
@Yasky, Điều đó miễn là bạn không sử dụng lại kết nối. Vì thực sự nó sẽ kéo dài trong cả buổi.
Pacerier

Và bạn không thể sử dụng lại bảng tạm thời. Vì vậy, nó không hữu ích cho lắm.
John


4
@John: Vâng, tốt, bạn có thể sử dụng lại nó, nhưng không phải trong cùng một truy vấn.
einpoklum

46

Bạn có thể đạt được điều này trong MySQL bằng WHILEvòng lặp:

SET @myArrayOfValue = '2,5,2,23,6,';

WHILE (LOCATE(',', @myArrayOfValue) > 0)
DO
    SET @value = ELT(1, @myArrayOfValue);
    SET @myArrayOfValue= SUBSTRING(@myArrayOfValue, LOCATE(',',@myArrayOfValue) + 1);

    INSERT INTO `EXEMPLE` VALUES(@value, 'hello');
END WHILE;

CHỈNH SỬA: Ngoài ra, bạn có thể làm điều đó bằng cách sử dụng UNION ALL:

INSERT INTO `EXEMPLE`
(
 `value`, `message`
)
(
 SELECT 2 AS `value`, 'hello' AS `message`
 UNION ALL
 SELECT 5 AS `value`, 'hello' AS `message`
 UNION ALL
 SELECT 2 AS `value`, 'hello' AS `message`
 UNION ALL
 ...
);

4
Không phải chỉ có thể thực hiện các vòng lặp trong các thủ tục được lưu trữ?
einpoklum

2
vâng đúng, có thể có bên trong các thủ tục, hàm và trình kích hoạt được lưu trữ.
Omesh

1
Vì vậy, tôi không thể sử dụng mã bạn đã cung cấp ... Tôi cần thứ gì đó có thể áp dụng chung hơn.
einpoklum

Bạn có thể viết một thủ tục lưu trữ mẫu và CALLnó.
Omesh

1
Tôi không nghĩ rằng mảng là cần thiết. Bạn có thể dễ dàng làm điều đó bằng cách sử dụng các bảng tạm thời hoặc UNION ALLkhông sử dụng thủ tục.
Omesh

28

Hãy thử sử dụng hàm FIND_IN_SET () của MySql, ví dụ:

SET @c = 'xxx,yyy,zzz';

SELECT * from countries 
WHERE FIND_IN_SET(countryname,@c);

Lưu ý: Bạn không phải SET biến trong StoredProcedure nếu bạn đang truyền tham số với các giá trị CSV.


Cẩn thận với các giới hạn chiều dài, có thể là khá thấp: stackoverflow.com/q/2567000/1333493
Nemo

19

Ngày nay, sử dụng mảng JSON sẽ là một câu trả lời hiển nhiên.

Vì đây là một câu hỏi cũ nhưng vẫn có liên quan nên tôi đã đưa ra một ví dụ ngắn. Các hàm JSON có sẵn kể từ mySQL 5.7.x / MariaDB 10.2.3

Tôi thích giải pháp này hơn ELT () vì nó thực sự giống một mảng hơn và 'mảng' này có thể được sử dụng lại trong mã.

Nhưng hãy cẩn thận: Nó (JSON) chắc chắn chậm hơn nhiều so với việc sử dụng một bảng tạm thời. Nó chỉ tiện dụng hơn. imo.

Đây là cách sử dụng một mảng JSON:

SET @myjson = '["gmail.com","mail.ru","arcor.de","gmx.de","t-online.de",
                "web.de","googlemail.com","freenet.de","yahoo.de","gmx.net",
                "me.com","bluewin.ch","hotmail.com","hotmail.de","live.de",
                "icloud.com","hotmail.co.uk","yahoo.co.jp","yandex.ru"]';

SELECT JSON_LENGTH(@myjson);
-- result: 19

SELECT JSON_VALUE(@myjson, '$[0]');
-- result: gmail.com

Và đây là một ví dụ nhỏ để hiển thị cách nó hoạt động trong một hàm / thủ tục:

DELIMITER //
CREATE OR REPLACE FUNCTION example() RETURNS varchar(1000) DETERMINISTIC
BEGIN
  DECLARE _result varchar(1000) DEFAULT '';
  DECLARE _counter INT DEFAULT 0;
  DECLARE _value varchar(50);

  SET @myjson = '["gmail.com","mail.ru","arcor.de","gmx.de","t-online.de",
                "web.de","googlemail.com","freenet.de","yahoo.de","gmx.net",
                "me.com","bluewin.ch","hotmail.com","hotmail.de","live.de",
                "icloud.com","hotmail.co.uk","yahoo.co.jp","yandex.ru"]';

  WHILE _counter < JSON_LENGTH(@myjson) DO
    -- do whatever, e.g. add-up strings...
    SET _result = CONCAT(_result, _counter, '-', JSON_VALUE(@myjson, CONCAT('$[',_counter,']')), '#');

    SET _counter = _counter + 1;
  END WHILE;

  RETURN _result;
END //
DELIMITER ;

SELECT example();

Bạn đang nói ELT chậm hơn hay JSON chậm hơn?
Kanagavelu Sugumar,

2
@Kanagavelu Sugumar: Tại thời điểm viết JSON chắc chắn là chậm hơn. Tôi đã chỉnh sửa câu trả lời để làm rõ ràng hơn.
SeparateReality

16

Không biết về các mảng, nhưng có một cách để lưu trữ danh sách được phân tách bằng dấu phẩy trong cột VARCHAR bình thường.

Và khi bạn cần tìm thứ gì đó trong danh sách đó, bạn có thể sử dụng hàm FIND_IN_SET () .


Nếu tôi muốn tìm tập hợp con trong một tập hợp, có cách nào không?
Akshay Vishnoi

Lấy làm tiếc! Tôi không chắc là có thể.
wormhit,

Bạn có giải pháp tốt nhất
Calvin

7
DELIMITER $$
CREATE DEFINER=`mysqldb`@`%` PROCEDURE `abc`()
BEGIN
  BEGIN 
    set @value :='11,2,3,1,'; 
    WHILE (LOCATE(',', @value) > 0) DO
      SET @V_DESIGNATION = SUBSTRING(@value,1, LOCATE(',',@value)-1); 
      SET @value = SUBSTRING(@value, LOCATE(',',@value) + 1); 
      select @V_DESIGNATION;
    END WHILE;
  END;
END$$
DELIMITER ;

2
Vui lòng giải thích cách sử dụng mã này và cách nó trả lời câu hỏi.
einpoklum

Như ở đây, bạn thực hiện thủ tục đơn giản cung cấp cho từng phần tử của chuỗi cụ thể đó hoạt động như mảng trong oracle.
Sagar Gangwal,

Tiên tri? Câu hỏi này không phải về Oracle. Ngoài ra, có vẻ như bạn đang xác định một mảng trong quy trình.
einpoklum

Kiểm tra lòng Syntex nó chỉ cho mysql
Sagar Gangwal

Đừng bỏ lỡ dấu phẩy cuối cùng!
Eagle_Eye

4

Tôi biết rằng đây là một phản hồi hơi muộn, nhưng gần đây tôi đã phải giải quyết một vấn đề tương tự và nghĩ rằng điều này có thể hữu ích cho những người khác.

Lý lịch

Hãy xem xét bảng dưới đây được gọi là 'mytable':

Bảng bắt đầu

Vấn đề là chỉ giữ 3 bản ghi mới nhất và xóa bất kỳ bản ghi cũ nào có systemid = 1 (có thể có nhiều bản ghi khác trong bảng với các giá trị systemid khác)

Sẽ rất tốt nếu bạn có thể làm điều này đơn giản bằng cách sử dụng câu lệnh

DELETE FROM mytable WHERE id IN (SELECT id FROM `mytable` WHERE systemid=1 ORDER BY id DESC LIMIT 3)

Tuy nhiên điều này vẫn chưa được hỗ trợ trong MySQL và nếu bạn thử điều này thì bạn sẽ gặp lỗi như

...doesn't yet support 'LIMIT & IN/ALL/SOME subquery'

Vì vậy, một giải pháp thay thế là cần thiết, theo đó một mảng giá trị được chuyển đến bộ chọn IN bằng cách sử dụng biến. Tuy nhiên, vì các biến cần phải là các giá trị đơn lẻ, tôi sẽ cần phải mô phỏng một mảng . Mẹo là tạo mảng dưới dạng danh sách giá trị được phân tách bằng dấu phẩy (chuỗi) và gán giá trị này cho biến như sau

SET @myvar := (SELECT GROUP_CONCAT(id SEPARATOR ',') AS myval FROM (SELECT * FROM `mytable` WHERE systemid=1 ORDER BY id DESC LIMIT 3 ) A GROUP BY A.systemid);

Kết quả được lưu trữ trong @myvar là

5,6,7

Tiếp theo, bộ chọn FIND_IN_SET được sử dụng để chọn từ mảng được mô phỏng

SELECT * FROM mytable WHERE FIND_IN_SET(id,@myvar);

Kết quả cuối cùng tổng hợp như sau:

SET @myvar := (SELECT GROUP_CONCAT(id SEPARATOR ',') AS myval FROM (SELECT * FROM `mytable` WHERE systemid=1 ORDER BY id DESC LIMIT 3 ) A GROUP BY A.systemid);
DELETE FROM mytable WHERE FIND_IN_SET(id,@myvar);

Tôi biết rằng đây là một trường hợp rất cụ thể. Tuy nhiên, nó có thể được sửa đổi để phù hợp với bất kỳ trường hợp nào khác khi một biến cần lưu trữ một mảng giá trị.

Tôi hy vọng rằng điều này sẽ giúp.


3

Có thể tạo một bảng bộ nhớ tạm thời với các cột (khóa, giá trị) nếu bạn muốn các mảng liên kết. Có một bảng bộ nhớ là điều gần nhất để có các mảng trong mysql


Umm, tôi không muốn mảng liên kết, chỉ mảng.
einpoklum

bạn có thể sử dụng một bảng bộ nhớ tạm thời chỉ với một cột và sau đó lặp qua các giá trị sử dụng con trỏ, đó là điều gần gũi nhất với việc sử dụng mảng và cho / trong khi vòng trong một ngôn ngữ lập trình không khai báo
Pavle Lekic

Ngôn ngữ thực sự có tính năng này, tức là, không có lý do cú pháp nào mà bạn không thể chọn một vectơ vào một biến giống như bạn chọn một đại lượng vô hướng vào nó.
einpoklum

3

Đây là cách tôi đã làm điều đó.

Đầu tiên, tôi đã tạo một hàm kiểm tra xem giá trị Dài / Số nguyên / bất kỳ có nằm trong danh sách các giá trị được phân tách bằng dấu phẩy hay không:

CREATE DEFINER = 'root'@'localhost' FUNCTION `is_id_in_ids`(
        `strIDs` VARCHAR(255),
        `_id` BIGINT
    )
    RETURNS BIT(1)
    NOT DETERMINISTIC
    CONTAINS SQL
    SQL SECURITY DEFINER
    COMMENT ''
BEGIN

  DECLARE strLen    INT DEFAULT 0;
  DECLARE subStrLen INT DEFAULT 0;
  DECLARE subs      VARCHAR(255);

  IF strIDs IS NULL THEN
    SET strIDs = '';
  END IF;

  do_this:
    LOOP
      SET strLen = LENGTH(strIDs);
      SET subs = SUBSTRING_INDEX(strIDs, ',', 1);

      if ( CAST(subs AS UNSIGNED) = _id ) THEN
        -- founded
        return(1);
      END IF;

      SET subStrLen = LENGTH(SUBSTRING_INDEX(strIDs, ',', 1));
      SET strIDs = MID(strIDs, subStrLen+2, strLen);

      IF strIDs = NULL or trim(strIds) = '' THEN
        LEAVE do_this;
      END IF;

  END LOOP do_this;

   -- not founded
  return(0);

END;

Vì vậy, bây giờ bạn có thể tìm kiếm ID trong danh sách ID được phân tách bằng dấu phẩy, như sau:

select `is_id_in_ids`('1001,1002,1003',1002);

Và bạn có thể sử dụng hàm này bên trong mệnh đề WHERE, như sau:

SELECT * FROM table1 WHERE `is_id_in_ids`('1001,1002,1003',table1_id);

Đây là cách duy nhất tôi tìm thấy để truyền một tham số "mảng" cho một THỦ TỤC.


2

Mảng không phải là điểm hiệu quả sao? Nếu bạn chỉ lặp qua các giá trị, tôi nghĩ con trỏ trên bảng tạm thời (hoặc vĩnh viễn) có ý nghĩa hơn việc tìm kiếm dấu phẩy, phải không? Cũng sạch hơn. Tra cứu "mysql DECLARE CURSOR".

Để truy cập ngẫu nhiên, một bảng tạm thời có khóa chính được lập chỉ mục bằng số. Thật không may, quyền truy cập nhanh nhất bạn sẽ nhận được là bảng băm, không phải quyền truy cập ngẫu nhiên thực sự.


Đây là một bình luận, không phải là một câu trả lời. Tôi đã không chỉ ra rằng đó là những gì tôi muốn làm với mảng.
einpoklum 27/09/18

2

Tôi ngạc nhiên là không có câu trả lời nào đề cập đến ELT / FIELD.

ELT / FIELD hoạt động rất giống với một mảng, đặc biệt nếu bạn có dữ liệu tĩnh.

FIND_IN_SET cũng hoạt động tương tự nhưng không có hàm bổ sung được tích hợp sẵn nhưng nó đủ dễ dàng để viết một hàm.

mysql> select elt(2,'AA','BB','CC');
+-----------------------+
| elt(2,'AA','BB','CC') |
+-----------------------+
| BB                    |
+-----------------------+
1 row in set (0.00 sec)

mysql> select field('BB','AA','BB','CC');
+----------------------------+
| field('BB','AA','BB','CC') |
+----------------------------+
|                          2 |
+----------------------------+
1 row in set (0.00 sec)

mysql> select find_in_set('BB','AA,BB,CC');
+------------------------------+
| find_in_set('BB','AA,BB,CC') |
+------------------------------+
|                            2 |
+------------------------------+
1 row in set (0.00 sec)

mysql>  SELECT SUBSTRING_INDEX(SUBSTRING_INDEX('AA,BB,CC',',',2),',',-1);
+-----------------------------------------------------------+
| SUBSTRING_INDEX(SUBSTRING_INDEX('AA,BB,CC',',',2),',',-1) |
+-----------------------------------------------------------+
| BB                                                        |
+-----------------------------------------------------------+
1 row in set (0.01 sec)

1

Điều này hoạt động tốt cho danh sách các giá trị:

SET @myArrayOfValue = '2,5,2,23,6,';

WHILE (LOCATE(',', @myArrayOfValue) > 0)
DO
SET @value = ELT(1, @myArrayOfValue);
    SET @STR = SUBSTRING(@myArrayOfValue, 1, LOCATE(',',@myArrayOfValue)-1);
    SET @myArrayOfValue = SUBSTRING(@myArrayOfValue, LOCATE(',', @myArrayOfValue) + 1);

    INSERT INTO `Demo` VALUES(@STR, 'hello');
END WHILE;

1

Cả hai phiên bản sử dụng bộ đều không hoạt động đối với tôi (được thử nghiệm với MySQL 5.5). Hàm ELT () trả về toàn bộ tập hợp. Xem xét câu lệnh WHILE chỉ khả dụng trong ngữ cảnh PROCEDURE, tôi đã thêm nó vào giải pháp của mình:

DROP PROCEDURE IF EXISTS __main__;

DELIMITER $
CREATE PROCEDURE __main__()
BEGIN
    SET @myArrayOfValue = '2,5,2,23,6,';

    WHILE (LOCATE(',', @myArrayOfValue) > 0)
    DO
        SET @value = LEFT(@myArrayOfValue, LOCATE(',',@myArrayOfValue) - 1);    
        SET @myArrayOfValue = SUBSTRING(@myArrayOfValue, LOCATE(',',@myArrayOfValue) + 1);
    END WHILE;
END;
$
DELIMITER ;

CALL __main__;

Thành thật mà nói, tôi không nghĩ đây là một thực hành tốt. Ngay cả khi nó thực sự cần thiết, điều này hầu như không thể đọc được và khá chậm.


1

Một cách khác để xem vấn đề tương tự. Hy vọng hữu ích

DELIMITER $$
CREATE PROCEDURE ARR(v_value VARCHAR(100))
BEGIN

DECLARE v_tam VARCHAR(100);
DECLARE v_pos VARCHAR(100);

CREATE TEMPORARY TABLE IF NOT EXISTS split (split VARCHAR(50));

SET v_tam = (SELECT (LENGTH(v_value) - LENGTH(REPLACE(v_value,',',''))));
SET v_pos = 1;

WHILE (v_tam >= v_pos)
DO
    INSERT INTO split 
    SELECT SUBSTRING_INDEX(SUBSTRING_INDEX(v_value,',',v_pos),',', -1);
    SET v_pos = v_pos + 1;
END WHILE;

SELECT * FROM split;

DROP TEMPORARY TABLE split;

END$$


CALL ARR('1006212,1006404,1003404,1006505,444,');

Trên thực tế, không rõ bạn đang nói gì ở đây. Câu hỏi này từ 7 năm trước đã có một số câu trả lời phù hợp. Xem xét xóa câu trả lời của bạn hoặc giải thích những gì bạn đang cố gắng nói trực tiếp / nói chung thay vì thông qua một ví dụ.
einpoklum 27/09/19

0

Trong phiên bản MYSQL sau 5.7.x, bạn có thể sử dụng kiểu JSON để lưu trữ một mảng. Bạn có thể nhận giá trị của một mảng bằng một khóa thông qua MYSQL.


7
Bạn có thể cho một ví dụ về cách tôi sẽ làm điều này?
einpoklum

0

Lấy cảm hứng từ hàm ELT (số chỉ mục, string1, string2, string3,…), tôi nghĩ ví dụ sau hoạt động như một ví dụ về mảng:

set @i := 1;
while @i <= 3
do
  insert into table(val) values (ELT(@i ,'val1','val2','val3'...));
set @i = @i + 1;
end while;

Hy vọng nó sẽ giúp.


0

Đây là một ví dụ cho MySQL để lặp qua một chuỗi được phân tách bằng dấu phẩy.

DECLARE v_delimited_string_access_index INT;
DECLARE v_delimited_string_access_value VARCHAR(255);
DECLARE v_can_still_find_values_in_delimited_string BOOLEAN;

SET v_can_still_find_values_in_delimited_string = true;
SET v_delimited_string_access_index = 0;
WHILE (v_can_still_find_values_in_delimited_string) DO
  SET v_delimited_string_access_value = get_from_delimiter_split_string(in_array, ',', v_delimited_string_access_index); -- get value from string
  SET v_delimited_string_access_index = v_delimited_string_access_index + 1;
  IF (v_delimited_string_access_value = '') THEN
    SET v_can_still_find_values_in_delimited_string = false; -- no value at this index, stop looping
  ELSE
    -- DO WHAT YOU WANT WITH v_delimited_string_access_value HERE
  END IF;
END WHILE;

điều này sử dụng get_from_delimiter_split_stringhàm được định nghĩa tại đây: https://stackoverflow.com/a/59666211/3068233


các chuỗi được phân tách bằng dấu phẩy đã được đề xuất - nhiều năm trước.
einpoklum

@einpoklum yep - và đây là một cách khác để tương tác với họ
Ulad Kasach

0

Một biến mảng có thực sự cần thiết không?

Tôi hỏi vì ban đầu tôi đã hạ cánh ở đây muốn thêm một mảng làm biến bảng MySQL. Tôi còn khá mới đối với thiết kế cơ sở dữ liệu và đang cố gắng nghĩ xem mình sẽ làm như thế nào theo kiểu ngôn ngữ lập trình điển hình.

Nhưng cơ sở dữ liệu thì khác. Tôi nghĩ rằng tôi muốn một mảng như một biến, nhưng hóa ra đó không phải là một thực hành cơ sở dữ liệu MySQL phổ biến.

Tiêu chuẩn thực hành

Giải pháp thay thế cho mảng là thêm một bảng bổ sung, sau đó tham chiếu bảng ban đầu của bạn bằng khóa ngoại.

Ví dụ, hãy tưởng tượng một ứng dụng theo dõi tất cả các mặt hàng mà mọi người trong một hộ gia đình muốn mua tại cửa hàng.

Các lệnh để tạo bảng mà tôi đã hình dung ban đầu sẽ trông giống như sau:

#doesn't work
CREATE TABLE Person(
  name VARCHAR(50) PRIMARY KEY
  buy_list ARRAY
);

Tôi nghĩ rằng tôi đã hình dung buy_list là một chuỗi các mục được phân tách bằng dấu phẩy hoặc tương tự như vậy.

Nhưng MySQL không có trường kiểu mảng, vì vậy tôi thực sự cần một cái gì đó như sau:

CREATE TABLE Person(
  name VARCHAR(50) PRIMARY KEY
);
CREATE TABLE BuyList(
  person VARCHAR(50),
  item VARCHAR(50),
  PRIMARY KEY (person, item),
  CONSTRAINT fk_person FOREIGN KEY (person) REFERENCES Person(name)
);

Ở đây chúng tôi xác định một ràng buộc có tên là fk_woman. Nó nói rằng trường 'người' trong BuyList là một khóa ngoại. Nói cách khác, đó là khóa chính trong một bảng khác, cụ thể là trường 'tên' trong bảng Người, là những gì biểu thị REFERENCES.

Chúng tôi cũng đã xác định sự kết hợp giữa người và mục là khóa chính, nhưng về mặt kỹ thuật thì điều đó không cần thiết.

Cuối cùng, nếu bạn muốn nhận tất cả các mục trong danh sách của một người, bạn có thể chạy truy vấn sau:

SELECT item FROM BuyList WHERE person='John';

Điều này cung cấp cho bạn tất cả các mục trong danh sách của John. Không cần mảng!


Giải pháp được chấp nhận của tôi sử dụng một bảng tạm thời.
einpoklum

Tất nhiên. Sau đó, tôi bao gồm câu trả lời này cho bất kỳ ai giống như tôi truy cập trang này để tìm cách tạo một kiểu mảng - những người ban đầu không hiểu tại sao mảng không phải là một kiểu trong MySQL. Có vẻ như đó là do thiết kế. Trường hợp chung không được trình bày ở đây vì vậy tôi bao gồm những gì tôi đã học được để những người khác hiểu rằng mảng thường không cần thiết. Tôi không mong bạn chọn câu trả lời của tôi. Nó phụ thuộc vào trường hợp sử dụng. Bạn có câu trả lời được chấp nhận cho một trường hợp sử dụng cụ thể và tôi đang cung cấp câu trả lời này cho trường hợp sử dụng chung.
kraftydevil

0

Nếu chúng ta có một bảng như vậy

mysql> select * from user_mail;
+------------+-------+
| email      | user | 
+------------+-------+-
| email1@gmail |     1 | 
| email2@gmail |     2 |
+------------+-------+--------+------------+

và bảng mảng:

mysql> select * from user_mail_array;
+------------+-------+-------------+
| email      | user | preferences |
+------------+-------+-------------+
| email1@gmail |     1 |           1 |
| email1@gmail |     1 |           2 |
| email1@gmail |     1 |           3 |
| email1@gmail |     1 |           4 |
| email2@gmail |     2 |           5 |
| email2@gmail |     2 |           6 |

Chúng ta có thể chọn các hàng của bảng thứ hai là một mảng với hàm CONCAT:

mysql> SELECT t1.*, GROUP_CONCAT(t2.preferences) AS preferences
     FROM user_mail t1,user_mail_array t2
       where t1.email=t2.email and t1.user=t2.user
     GROUP BY t1.email,t1.user;

+------------+-------+--------+------------+-------------+
| email      | user | preferences |
+------------+-------+--------+------------+-------------+
|email1@gmail |     1 | 1,3,2,4     |
|email2@gmail |     2 | 5,6         |
+------------+-------+--------+------------+-------------+

Tôi nghĩ là trùng lặp với câu trả lời của Clinton.
einpoklum

-2

Tôi nghĩ rằng tôi có thể cải thiện câu trả lời này. Thử đi:

Tham số 'Pranks' là một CSV. I E. '1,2,3,4 ..... vv'

CREATE PROCEDURE AddRanks(
IN Pranks TEXT
)
BEGIN
  DECLARE VCounter INTEGER;
  DECLARE VStringToAdd VARCHAR(50);
  SET VCounter = 0;
  START TRANSACTION;
  REPEAT
    SET VStringToAdd = (SELECT TRIM(SUBSTRING_INDEX(Pranks, ',', 1)));
    SET Pranks = (SELECT RIGHT(Pranks, TRIM(LENGTH(Pranks) - LENGTH(SUBSTRING_INDEX(Pranks, ',', 1))-1)));
    INSERT INTO tbl_rank_names(rank)
    VALUES(VStringToAdd);
    SET VCounter = VCounter + 1;
  UNTIL (Pranks = '')
  END REPEAT;
  SELECT VCounter AS 'Records added';
  COMMIT;
END;

Phương pháp này làm cho chuỗi giá trị CSV được tìm kiếm dần dần ngắn hơn với mỗi lần lặp lại của vòng lặp, tôi tin rằng sẽ tốt hơn cho việc tối ưu hóa.


Bạn đang đề cập đến 'câu trả lời này' là gì? Ngoài ra, bạn không cần phải có tệp CSV.
einpoklum

Tôi không đề cập đến tệp CSV, tôi đang đề cập đến giá trị CSV chẳng hạn như '1,2,3,4 ... vv'
user2288580

-2

Tôi sẽ thử một cái gì đó như thế này cho nhiều bộ sưu tập. Tôi là người mới bắt đầu sử dụng MySQL. Xin lỗi về tên chức năng, không thể quyết định tên nào là tốt nhất.

delimiter //

drop  procedure init_
//
create procedure init_()
begin
  CREATE TEMPORARY TABLE if not exists 
    val_store(  
    realm  varchar(30) 
    ,  id  varchar(30) 
    ,  val   varchar(255) 
    ,  primary key ( realm , id )
    );
end;
//

drop function if exists get_
//
create function get_( p_realm varchar(30) , p_id varchar(30) )
  returns varchar(255)
  reads sql data
begin 
  declare ret_val varchar(255);
  declare continue handler for 1146 set ret_val = null;
  select val into ret_val from val_store where id = p_id;
  return ret_val;
end;
//

drop procedure if exists set_
//
create procedure set_( p_realm varchar(30) , p_id varchar(30) , p_val varchar(255) )
begin
  call init_(); 
  insert into val_store (realm,id,val) values (p_realm , p_id , p_val) on duplicate key update val = p_val;
end;
//

drop   procedure if exists remove_
//
create procedure remove_( p_realm varchar(30) , p_id varchar(30) )
begin
  call init_();
  delete from val_store where realm = p_realm and id = p_id;
end;
//

drop   procedure if exists erase_
//
create procedure erase_( p_realm varchar(30) ) 
begin
  call init_();
  delete from val_store where realm = p_realm;
end;
//

call set_('my_array_table_name','my_key','my_value');

select get_('my_array_table_name','my_key');

Tôi nghĩ rằng tôi hiểu những gì bạn đang đề xuất, nhưng điều này là khá khó sử dụng và có lẽ cũng vô cùng chậm ...
einpoklum

Tôi không thể xác nhận hoặc loại bỏ nó mà không cần kiểm tra căng thẳng. Về cơ bản nó là một tra cứu khóa chính và chèn vào một bảng tạm thời (hoặc bảng bình thường). Tôi sẽ sử dụng nó cho đến khi tôi gặp sự cố hoặc tìm ra cách tốt hơn; nhưng tôi làm những việc kỳ lạ như viết trình biên dịch và trò chơi hoàn toàn trong Oracle PL / SQL.
Dave

-2

Thay vì Lưu dữ liệu dưới dạng một mảng hoặc chỉ trong một hàng, bạn nên tạo các hàng khác nhau cho mọi giá trị nhận được. Điều này sẽ làm cho nó dễ hiểu hơn nhiều thay vì gộp tất cả lại với nhau.


Hãy chia sẻ cách làm điều này
Nico Haase

-5

Bạn đã thử sử dụng serialize () của PHP chưa? Điều đó cho phép bạn lưu trữ nội dung của mảng của một biến trong một chuỗi mà PHP hiểu và an toàn cho cơ sở dữ liệu (giả sử bạn đã thoát khỏi nó trước).

$array = array(
    1 => 'some data',
    2 => 'some more'
);

//Assuming you're already connected to the database
$sql = sprintf("INSERT INTO `yourTable` (`rowID`, `rowContent`) VALUES (NULL, '%s')"
     ,  serialize(mysql_real_escape_string($array, $dbConnection)));
mysql_query($sql, $dbConnection) or die(mysql_error());

Bạn cũng có thể làm điều tương tự mà không cần một mảng được đánh số

$array2 = array(
    'something' => 'something else'
);

hoặc là

$array3 = array(
    'somethingNew'
);

7
Tôi không làm việc với PHP, vì vậy điều đó không thực sự phù hợp với tôi.
einpoklum

1
Sử dụng JSON thay vì tuần tự hóa. Nó chung chung hơn và không phụ thuộc vào ngôn ngữ.
Rick James
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.