清单中的MySQL REPEAT过程

时间:2019-03-23 15:26:29

标签: mysql repeat

注意:在这个问题上,我仅对一般情况感兴趣,但为简单起见,我将考虑一个具体情况。

让我们想象一下,我想用从列表中提取的列创建一个表。

因此,我想从列表中批量创建表:

SET @list = "foo,bar,baz";
SET @query = '';

SET @query = 'CREATE TABLE foobar (';
-- FOREACH @list ASs name
SET @query = CONCAT(@query, name, ' INT,')
-- ENDFOREACH

SET @query = CONCAT(@query, ')'); -- Yes I need to remove the extra semicolon

PREPARE stm1;
FROM @query;
EXECUTE stm1;
DEALLOCATE PREPARE stm1;

不幸的是,我还没有找到重复的方法。我当前的解决方案是使用我可以使用的所有名称创建一个虚拟表:

CREATE TABLE dummy (name VARCHAR(100));
INSERT INTO dummy (`name`) VALUES ('foo'), ('bar'), ('baz');

然后我可以做:

SELECT name FROM dummy WHERE FIND_IN_SET(name, @list);

我可以这样做:

SELECT 
    @query := CONCAT(@query, ' ', 
   '...'
) 
FROM dummy 
WHERE FIND_IN_SET(name, @list);

我有办法简化吗?

2 个答案:

答案 0 :(得分:0)

一种解决方案是使用此技巧:


class CommentSerializer < ActiveModel::Serializer

  attributes :id, :body, :likes, :user_id

  belongs_to :commentable, :polymorphic => true
  belongs_to :sighting
  has_many :comments, as: :commentable
end

然后您可以简单地调用过程:

SET @query = '';
delimiter |
CREATE PROCEDURE foo(IN names VARCHAR(100))
BEGIN
SET @myArrayOfValue = CONCAT(names, ',');
    WHILE (LOCATE(',', @myArrayOfValue) > 0)
    DO
        SET @value = LEFT(@myArrayOfValue, LOCATE(',',@myArrayOfValue) - 1);    
        SET @myArrayOfValue = SUBSTRING(@myArrayOfValue, LOCATE(',',@myArrayOfValue) + 1);

        -- BEGIN The code you want to repeat
        SET @query = CONCAT(@query, ' CREATE TABLE ', @value, ' ( id INT AUTO_INCREMENT PRIMARY KEY);');
        -- END
    END WHILE;
END
|

答案 1 :(得分:-1)

您不能使用PREPARE来准备多个用分号分隔的查询。您必须一次执行一次。

mysql> set @sql = "select * from foo ; select * from bar";
Query OK, 0 rows affected (0.01 sec)

mysql> prepare stmt from @sql;
ERROR 1064 (42000): You have an error in your SQL syntax; 
check the manual that corresponds to your MySQL server version for the right syntax
to use near 'select * from bar' at line 1

我不知道为什么这么多开发人员想要在MySQL中使用存储过程。他们太可怕了。没有包,没有用户定义的数据类型,没有编译器,没有调试器,并且文档很差。

您描述的任务更容易以任何脚本语言实现。选择您喜欢的语言,其中任何一种都和其他语言一样能胜任这项任务。

以下是Ruby中的示例:

require 'Mysql2'
db = Mysql2::Client.new(:host => "localhost", :username => "root", :database => "test")

["foo", "bar", "baz"].each do |table|
  db.query("CREATE TABLE `#{table}` ( id INT AUTO_INCREMENT PRIMARY KEY )")
end

将此与棘手的字符串拆分和连接进行比较,准备并执行使用存储过程时必需的操作。

除异常情况外,我不使用MySQL存储过程,并且不建议其他人使用它们。我使用存储过程的一种情况是,授予用户针对他们没有查看权限的数据运行一些SQL语句的能力。


这是一个在MySQL 5.6上测试过的解决方案:

DELIMITER ;;
CREATE PROCEDURE the_worst_solution_for_this_task(IN tablenames TEXT)
BEGIN
 DECLARE i INT;
 DECLARE tablename VARCHAR(64);
 SELECT LENGTH(tablenames)-LENGTH(REPLACE(tablenames, ',', ''))+1 INTO i;
 WHILE i > 0
 DO
  SELECT TRIM(SUBSTRING_INDEX(SUBSTRING_INDEX(tablenames, ',', i), ',', -1)) INTO tablename;
  SET @sql = CONCAT('CREATE TABLE `', tablename, '` (id INT AUTO_INCREMENT PRIMARY KEY)');
  PREPARE stmt FROM @sql;
  EXECUTE stmt;
  DEALLOCATE PREPARE stmt;
  SET i = i - 1;
 END WHILE;
END;;
DELIMITER ;

CALL the_worst_solution_for_this_task('foo,bar,baz');

SHOW TABLES;
+----------------+
| Tables_in_test |
+----------------+
| bar            |
| baz            |
| foo            |
+----------------+