注意:在这个问题上,我仅对一般情况感兴趣,但为简单起见,我将考虑一个具体情况。
让我们想象一下,我想用从列表中提取的列创建一个表。
因此,我想从列表中批量创建表:
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);
我有办法简化吗?
答案 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 |
+----------------+