使用准备和执行
Using Prepare and Execute
我有一个 table 有训练记录。每条记录都有一个带有 Agency 值的字段。我还有另一个 table 的代理值。我想将每个机构的记录导出到 CSV 文件中。有超过 200 万条记录,所以我不想导出整个 table 并手动执行。
我创建了一个存储过程,它使用游标从 agency_codes table 中提取一个值,并将该值用于 的 select 语句中WHERE 子句和 INTO OUTFILE 名称的一部分。
该过程有效,但仅适用于 agency_codes table 中的前两个值。在第三个(ACB)值上,它给出错误 Unknown column 'ACB' in 'where clause' 我很困惑为什么它使用前两个值然后停止第三.
程序如下:
DELIMITER $$
DROP PROCEDURE IF EXISTS export_csv $$
CREATE PROCEDURE export_csv()
BEGIN
DECLARE agency_name VARCHAR(255);
DECLARE exit_loop BOOLEAN;
DECLARE agency_cursor CURSOR FOR
SELECT agency FROM agency_codes;
DECLARE CONTINUE HANDLER FOR NOT FOUND SET exit_loop = TRUE;
OPEN agency_cursor;
agency_loop: LOOP
FETCH agency_cursor INTO agency_name;
SET @sql_text = Concat("(select 'class_code','course_code','course_name','course_type','username','grade_type','score','letter_grade','is_passed','completion_date','completion_status','registration_date','registration_entry_status','registration_type','comment','first_name','last_name','class_name','agency') Union (select class_code,course_code,course_name,course_type,username,grade_type,score,letter_grade,is_passed,completion_date,completion_status,registration_date,registration_entry_status,registration_type,comment,first_name,last_name,class_name,agency from hrdis_oru where hrdis_oru.agency =", agency_name," into outfile 'C:/HDD/",agency_name,".csv' fields enclosed by '\"' terminated by ',' escaped by '\"' lines terminated by '\r\n')");
prepare s1 from @sql_text;
execute s1;
deallocate prepare s1;
IF exit_loop THEN
CLOSE agency_cursor;
LEAVE agency_loop;
END IF;
END LOOP agency_loop;
END $$
DELIMITER ;
我的代理商 table 中的前几个值是:
- 17
- 303
- ACB
- 精算师
- agr
- 目标
任何帮助都会很棒。谢谢
如果您考虑 @sql_text
将在每次迭代中保持什么值,问题应该立即显而易见。为清楚起见添加一些空格:
(
select 'class_code','course_code','course_name','course_type','username',
'grade_type','score','letter_grade','is_passed','completion_date',
'completion_status','registration_date','registration_entry_status',
'registration_type','comment','first_name','last_name','class_name',
'agency'
) Union (
select class_code,course_code,course_name,course_type,username,
grade_type,score,letter_grade,is_passed,completion_date,
completion_status,registration_date,registration_entry_status,
registration_type,comment,first_name,last_name,class_name,
agency
from hrdis_oru
where hrdis_oru.agency =ACB
into outfile 'C:/HDD/ACB.csv'
fields enclosed by '\"'
terminated by ','
escaped by '\"'
lines terminated by '\r\n'
)
特别注意,where htdis_oru.agency =ACB
。
由于 ACB
没有被引用,MySQL 将其解析为模式对象标识符并在找不到任何这样命名的对象时抱怨(纯数字不是这种情况机构名称,因为它们被解析为整数,随后得到 cast to strings during expression evaluation).
为了 MySQL 正确地将非数字值解析为字符串文字,它们必须被引用:
... where hrdis_oru.agency ='", agency_name, "' ...
^ ^
自然地,这提出了一个问题,应该 agency_name
包含 '
字符串引号字符——任何此类出现当然必须 escaped. MySQL handily provides a QUOTE()
函数正是为了这个目的:
... where hrdis_oru.agency =", QUOTE(agency_name), " ...
但是,为了防止可能的 SQL 注入攻击,您确实应该 参数化 您准备好的语句:
FETCH agency_cursor INTO @agency_name;
(您不再需要DECLARE agency_name
);然后:
... where hrdis_oru.agency = ? into outfile CONCAT('C:/HDD/', ?, '.csv') ...
其次是:
PREPARE s1 FROM @sql_text;
EXECUTE s1 USING @agency_name, @agency_name;
DEALLOCATE PREPARE s1;
请注意,您现在还可以 PREPARE
语句 before 进入循环并在循环内简单地 EXECUTE
它(具有适当的值)——这应该会产生轻微的性能改进。退出循环后记得DEALLOCATE
。
最后一点:您应该在 FETCH
命令后立即检查 exit_loop
— 否则您最终会尝试执行 SELECT ... INTO OUTFILE
在没有更多代理的情况下最后一次声明。
可能还值得注意的是,在这种情况下,您根本不需要使用准备好的语句。您可以简单地执行以下操作:
CREATE PROCEDURE export_csv() BEGIN
DECLARE agency_name VARCHAR(255);
DECLARE agency_cursor CURSOR FOR SELECT agency FROM agency_codes;
DECLARE EXIT HANDLER FOR NOT FOUND CLOSE agency_cursor;
OPEN agency_cursor;
LOOP
FETCH agency_cursor INTO agency_name;
SELECT 'class_code','course_code','course_name','course_type','username',
'grade_type','score','letter_grade','is_passed','completion_date',
'completion_status','registration_date','registration_entry_status',
'registration_type','comment','first_name','last_name','class_name'
UNION ALL
SELECT class_code,course_code,course_name,course_type,username,
grade_type,score,letter_grade,is_passed,completion_date,
completion_status,registration_date,registration_entry_status,
registration_type,comment,first_name,last_name,class_name
FROM hrdis_oru
WHERE agency = agency_name
INTO OUTFILE CONCAT('C:/HDD/', agency_name, '.csv')
FIELDS ENCLOSED BY '"'
TERMINATED BY ','
ESCAPED BY '"'
LINES TERMINATED BY '\r\n';
END LOOP;
END
我有一个 table 有训练记录。每条记录都有一个带有 Agency 值的字段。我还有另一个 table 的代理值。我想将每个机构的记录导出到 CSV 文件中。有超过 200 万条记录,所以我不想导出整个 table 并手动执行。
我创建了一个存储过程,它使用游标从 agency_codes table 中提取一个值,并将该值用于 的 select 语句中WHERE 子句和 INTO OUTFILE 名称的一部分。
该过程有效,但仅适用于 agency_codes table 中的前两个值。在第三个(ACB)值上,它给出错误 Unknown column 'ACB' in 'where clause' 我很困惑为什么它使用前两个值然后停止第三.
程序如下:
DELIMITER $$
DROP PROCEDURE IF EXISTS export_csv $$
CREATE PROCEDURE export_csv()
BEGIN
DECLARE agency_name VARCHAR(255);
DECLARE exit_loop BOOLEAN;
DECLARE agency_cursor CURSOR FOR
SELECT agency FROM agency_codes;
DECLARE CONTINUE HANDLER FOR NOT FOUND SET exit_loop = TRUE;
OPEN agency_cursor;
agency_loop: LOOP
FETCH agency_cursor INTO agency_name;
SET @sql_text = Concat("(select 'class_code','course_code','course_name','course_type','username','grade_type','score','letter_grade','is_passed','completion_date','completion_status','registration_date','registration_entry_status','registration_type','comment','first_name','last_name','class_name','agency') Union (select class_code,course_code,course_name,course_type,username,grade_type,score,letter_grade,is_passed,completion_date,completion_status,registration_date,registration_entry_status,registration_type,comment,first_name,last_name,class_name,agency from hrdis_oru where hrdis_oru.agency =", agency_name," into outfile 'C:/HDD/",agency_name,".csv' fields enclosed by '\"' terminated by ',' escaped by '\"' lines terminated by '\r\n')");
prepare s1 from @sql_text;
execute s1;
deallocate prepare s1;
IF exit_loop THEN
CLOSE agency_cursor;
LEAVE agency_loop;
END IF;
END LOOP agency_loop;
END $$
DELIMITER ;
我的代理商 table 中的前几个值是:
- 17
- 303
- ACB
- 精算师
- agr
- 目标
任何帮助都会很棒。谢谢
如果您考虑 @sql_text
将在每次迭代中保持什么值,问题应该立即显而易见。为清楚起见添加一些空格:
(
select 'class_code','course_code','course_name','course_type','username',
'grade_type','score','letter_grade','is_passed','completion_date',
'completion_status','registration_date','registration_entry_status',
'registration_type','comment','first_name','last_name','class_name',
'agency'
) Union (
select class_code,course_code,course_name,course_type,username,
grade_type,score,letter_grade,is_passed,completion_date,
completion_status,registration_date,registration_entry_status,
registration_type,comment,first_name,last_name,class_name,
agency
from hrdis_oru
where hrdis_oru.agency =ACB
into outfile 'C:/HDD/ACB.csv'
fields enclosed by '\"'
terminated by ','
escaped by '\"'
lines terminated by '\r\n'
)
特别注意,where htdis_oru.agency =ACB
。
由于 ACB
没有被引用,MySQL 将其解析为模式对象标识符并在找不到任何这样命名的对象时抱怨(纯数字不是这种情况机构名称,因为它们被解析为整数,随后得到 cast to strings during expression evaluation).
为了 MySQL 正确地将非数字值解析为字符串文字,它们必须被引用:
... where hrdis_oru.agency ='", agency_name, "' ...
^ ^
自然地,这提出了一个问题,应该 agency_name
包含 '
字符串引号字符——任何此类出现当然必须 escaped. MySQL handily provides a QUOTE()
函数正是为了这个目的:
... where hrdis_oru.agency =", QUOTE(agency_name), " ...
但是,为了防止可能的 SQL 注入攻击,您确实应该 参数化 您准备好的语句:
FETCH agency_cursor INTO @agency_name;
(您不再需要DECLARE agency_name
);然后:
... where hrdis_oru.agency = ? into outfile CONCAT('C:/HDD/', ?, '.csv') ...
其次是:
PREPARE s1 FROM @sql_text;
EXECUTE s1 USING @agency_name, @agency_name;
DEALLOCATE PREPARE s1;
请注意,您现在还可以 PREPARE
语句 before 进入循环并在循环内简单地 EXECUTE
它(具有适当的值)——这应该会产生轻微的性能改进。退出循环后记得DEALLOCATE
。
最后一点:您应该在 FETCH
命令后立即检查 exit_loop
— 否则您最终会尝试执行 SELECT ... INTO OUTFILE
在没有更多代理的情况下最后一次声明。
可能还值得注意的是,在这种情况下,您根本不需要使用准备好的语句。您可以简单地执行以下操作:
CREATE PROCEDURE export_csv() BEGIN
DECLARE agency_name VARCHAR(255);
DECLARE agency_cursor CURSOR FOR SELECT agency FROM agency_codes;
DECLARE EXIT HANDLER FOR NOT FOUND CLOSE agency_cursor;
OPEN agency_cursor;
LOOP
FETCH agency_cursor INTO agency_name;
SELECT 'class_code','course_code','course_name','course_type','username',
'grade_type','score','letter_grade','is_passed','completion_date',
'completion_status','registration_date','registration_entry_status',
'registration_type','comment','first_name','last_name','class_name'
UNION ALL
SELECT class_code,course_code,course_name,course_type,username,
grade_type,score,letter_grade,is_passed,completion_date,
completion_status,registration_date,registration_entry_status,
registration_type,comment,first_name,last_name,class_name
FROM hrdis_oru
WHERE agency = agency_name
INTO OUTFILE CONCAT('C:/HDD/', agency_name, '.csv')
FIELDS ENCLOSED BY '"'
TERMINATED BY ','
ESCAPED BY '"'
LINES TERMINATED BY '\r\n';
END LOOP;
END