如何在MySQL中模拟数组变量?

ein*_*ica 76 mysql arrays variables set temp-tables

似乎是MySQL没有数组变量.我应该用什么呢?


似乎有两种选择建议:集类型标量临时表.我联系的问题暗示了前者.但是使用这些而不是数组变量是一种好习惯吗?或者,如果我使用集合,那么基于集合的成语相当于foreach什么?

ein*_*ica 65

好吧,我一直在使用临时表而不是数组变量.不是最好的解决方案,但它确实有效.

请注意,您无需正式定义其字段,只需使用SELECT创建它们:

CREATE TEMPORARY TABLE IF NOT EXISTS my_temp_table
SELECT first_name FROM people WHERE last_name = 'Smith';
Run Code Online (Sandbox Code Playgroud)

(另请参阅从select语句创建临时表而不使用Create Table.)

  • @John:是的,好吧,你_can_重用它,但不是在同一个查询中. (4认同)
  • @Yasky,前提是您不重用连接。因为确实它将持续整个**会话。 (2认同)

Ome*_*esh 38

您可以使用WHILE循环在MySQL中实现此目的:

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;
Run Code Online (Sandbox Code Playgroud)

编辑:或者你可以使用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
 ...
);
Run Code Online (Sandbox Code Playgroud)

  • 是否只能在存储过程中循环? (4认同)
  • 是的,它可能在存储过程,函数和触发器内部。 (2认同)

Him*_*arg 22

尝试使用MySql的FIND_IN_SET()函数,例如

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

SELECT * from countries 
WHERE FIND_IN_SET(countryname,@c);
Run Code Online (Sandbox Code Playgroud)

注意:如果要使用CSV值传递参数,则不必在StoredProcedure中设置SET变量.


wor*_*hit 15

不知道数组,但有一种方法可以在普通的VARCHAR列中存储逗号分隔的列表.

当您需要在该列表中找到某些内容时,您可以使用FIND_IN_SET()函数.


Sep*_*ity 12

现在使用JSON数组将是一个明显的答案.

由于这是一个古老但仍然相关的问题,我提出了一个简短的例子.自mySQL 5.7.x/MariaDB 10.2.3起,JSON函数可用

我比ELT()更喜欢这个解决方案,因为它更像是一个数组,这个'数组'可以在代码中重用.

但要小心:它(JSON)肯定比使用临时表慢得多.它更方便.海事组织.

以下是如何使用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
Run Code Online (Sandbox Code Playgroud)

这里有一个小例子来说明它在函数/过程中是如何工作的:

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();
Run Code Online (Sandbox Code Playgroud)

  • @Kanagavelu Sugumar:在编写JSON时,速度肯定要慢一些。我编辑了答案以使其更清楚。 (2认同)

Sag*_*wal 6

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 ;
Run Code Online (Sandbox Code Playgroud)

  • 请说明如何使用此代码以及如何回答该问题。 (2认同)

Cli*_*ton 5

我知道这有点晚了,但我最近不得不解决一个类似的问题,并认为这可能对其他人有用。

背景

考虑下面名为“mytable”的表格:

起始表

问题是只保留最新的 3 条记录并删除 systemid=1 的所有旧记录(表中可能有许多其他记录具有其他 systemid 值)

最好是你可以简单地使用语句来做到这一点

DELETE FROM mytable WHERE id IN (SELECT id FROM `mytable` WHERE systemid=1 ORDER BY id DESC LIMIT 3)
Run Code Online (Sandbox Code Playgroud)

但是,MySQL 尚不支持此功能,如果您尝试此操作,则会出现类似错误

...doesn't yet support 'LIMIT & IN/ALL/SOME subquery'
Run Code Online (Sandbox Code Playgroud)

因此需要一种变通方法,即使用变量将一组值传递给 IN 选择器。但是,由于变量需要是单个值,我需要模拟一个数组诀窍是将数组创建为逗号分隔的值列表(字符串)并将其分配给变量,如下所示

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);
Run Code Online (Sandbox Code Playgroud)

存储在@myvar 中的结果是

5,6,7

接下来使用 FIND_IN_SET 选择器从模拟数组中进行选择

SELECT * FROM mytable WHERE FIND_IN_SET(id,@myvar);
Run Code Online (Sandbox Code Playgroud)

合并后的最终结果如下:

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);
Run Code Online (Sandbox Code Playgroud)

我知道这是一个非常具体的案例。然而,它可以被修改以适应变量需要存储值数组的任何其他情况。

我希望这个对你有用。

  • 你做得很好!感谢您,我发现了 4 个新的 SQL 函数! (2认同)