我有一个填充了ID号的表,我需要循环遍历,并在预准备语句中用作变量。我不知道是否需要为此使用存储过程,或者如果常规查询可以执行此操作。这是一个简单的例子。
SELECT id from var_list;
loop through @ID = var_list.id ....
SET @s1 = "SELECT * FROM data WHERE id = @ID";
PREPARE stmt1 FROM @s1;
EXECUTE stmt1;
DEALLOCATE PREPARE stmt1;
正如评论中所提到的,我只需要这个来导出一些数据,我在表中有大约50-100个ID,并且编写了一个查询,一次一个地将文件导出到服务器
EDIT 我计划使用类似的东西将每次迭代的结果转储到文件中。
INTO OUTFILE '/tmp/orders.csv'
FIELDS TERMINATED BY ','
ENCLOSED BY '"'
LINES TERMINATED BY '\n'
答案 0 :(得分:2)
正如其他人已经建议的那样,我们通常主要出于性能原因避免循环结果集 RBAR (通过痛苦排行)。我们不想养成循环结果集的习惯。但是,这并没有回答你提出的问题。
要回答您提出的问题,这里是MySQL存储程序的基本示例,该程序使用CURSOR单独处理查询返回的行。 MySQL不支持匿名块,所以唯一的方法是在MySQL存储程序中,如PROCEDURE
DELIMITER $$
CREATE PROCEDURE loop_through_var_list
BEGIN
DECLARE done INT DEFAULT 0;
DECLARE v_id INT DEFAULT NULL;
DECLARE csr_var_list CURSOR FOR SELECT id FROM var_list ORDER BY id;
DECLARE CONTINUE HANDLER FOR NOT FOUND SET done = 1;
OPEN csr_var_list;
get_id: LOOP
FETCH csr_var_list INTO v_id;
IF done = 1 THEN
LEAVE get_id;
END IF;
-- at this point, we have an id value in v_id, so we can do whatever
SET @s1 = CONCAT('SELECT ... WHERE id =''', v_id, ''' ...');
END LOOP get_id;
CLOSE csr_var_list;
END$$
DELIMITER ;
执行程序:
CALL loop_through_var_list();
注意:在MySQL中处理CURSOR的语法与其他数据库有很大不同。
要获得"循环",我们需要使用LOOP ... END LOOP
构造。
但为了防止该循环永远运行,我们需要一个允许我们退出循环的LEAVE语句。
我们使用条件测试来确定何时离开。在这个例子中,我们想在完成最后一行的处理后退出。
当没有更多行要提取时,FETCH
将抛出异常。
我们"赶上" CONTINUE HANDLER中的异常(由于某些神秘的原因,"处理程序"必须声明最后的事情;如果我们尝试在HANDLER之后声明某些东西(除了另一个HANDLER之外),MySQL会抛出错误。
当MySQL抛出"没有更多行"异常,触发处理程序代码。在此示例中,我们只是将变量(名为done
)设置为值。
因为它是"继续"处理程序,处理在抛出异常的语句处开始备份,在这种情况下,它将是FETCH之后的语句。所以,我们要做的第一件事就是检查我们是否已经完成了#34;或不。如果我们已经完成",那么我们退出循环,并关闭光标。
否则,我们知道我们从名为id
的过程变量中存储了来自var_list
的{{1}}值。所以现在我们可以做任何我们想做的事。看起来你想把一些SQL文本放到用户定义的变量中(包括在v_id的值中的SQL文本,然后是PREPARE,EXECUTE和DEALLOCATE PREPARE。
请务必使用适当的数据类型声明v_id
变量,该数据类型与v_id
中id
列的数据类型相匹配,我只是假设它是'是一个INT。
当我们到达循环结束时,MySQL"循环"回到循环的开头,然后我们再去。
在循环体中,您可能希望将CONCAT v_id转换为要执行的SQL文本。看起来你已经掌握了PREPARE,DEALLOCATE准备。对于测试,您可能希望在游标声明中的SELECT上添加LIMIT子句,然后执行简单的SELECT v_id;在添加更多代码之前,只是为了验证循环是否正常工作。
<强>后续强>
我想提到另一种替代方法,即基于模板运行一系列语句,替换单个SQL select语句提供的值...
例如,如果我有这个模板:
var_list
我需要用SELECT语句返回的列表中的特定id值替换@ID的出现,例如:
SELECT *
INTO OUTFILE '/tmp/orders_@ID.csv'
FIELDS TERMINATED BY ',' ENCLOSED BY '"'
LINES TERMINATED BY '\n'
FROM data
WHERE id = @ID
ORDER BY 1
我可能不会使用带有CURSOR循环的MySQL存储程序,我会使用不同的方法。
我使用SELECT语句生成一组可以执行的SQL语句。假设SELECT id
FROM var_list
WHERE id IS NOT NULL
GROUP BY id
是整数类型,我可能会这样做:
id
对于从SELECT CONCAT(' SELECT *
INTO OUTFILE ''/tmp/orders_',s.id,'.csv''
FIELDS TERMINATED BY '','' ENCLOSED BY ''"''
LINES TERMINATED BY ''\n''
FROM data
WHERE id = ',s.id,'
ORDER BY 1;') AS `stmt`
FROM ( SELECT v.id
FROM var_list v
WHERE v.id IS NOT NULL
GROUP BY v.id
) s
ORDER BY s.id
返回的id
的每个值,该语句返回可以(并且需要)执行的SQL SELECT语句的文本。将其捕获到文本文件中会给我一个我可以运行的SQL脚本。
答案 1 :(得分:1)
使用简单的查询,例如:
SELECT *
FROM data
WHERE id IN (
SELECT id
FROM var_list
)