Mysql 使用Prepare和Execute
我有一张有训练记录的桌子。每个记录都有一个带有代理值的字段。我还有另外一张表,上面有公正的机构价值观。我想将每个机构的记录导出为CSV文件。有超过200万条记录,所以我不想导出整个表并手动执行 我创建了一个存储过程,它使用游标从agency_codes表中提取一个值,并在WHERE子句和INTO OUTPILE名称的一部分的select语句中使用该值 该程序有效,但仅适用于机构代码表中的前两个值。在第三个ACB值上,它在“where子句”中给出了错误未知列“ACB”。我不明白为什么它与前两个值一起工作,然后与第三个值一起停止 程序如下:Mysql 使用Prepare和Execute,mysql,stored-procedures,cursor,into-outfile,Mysql,Stored Procedures,Cursor,Into Outfile,我有一张有训练记录的桌子。每个记录都有一个带有代理值的字段。我还有另外一张表,上面有公正的机构价值观。我想将每个机构的记录导出为CSV文件。有超过200万条记录,所以我不想导出整个表并手动执行 我创建了一个存储过程,它使用游标从agency_codes表中提取一个值,并在WHERE子句和INTO OUTPILE名称的一部分的select语句中使用该值 该程序有效,但仅适用于机构代码表中的前两个值。在第三个ACB值上,它在“where子句”中给出了错误未知列“ACB”。我不明白为什么它与前两个值一
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 ;
我的代理表中的前几个值是:
17
303
ACB
精算师
agr
目标
任何帮助都会很好。谢谢。如果您想一想@sql\u 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'
)
特别注意,其中htdis_或U.agency=ACB
由于ACB没有被引用,MySQL将其解析为模式对象标识符,并在找不到任何这样的命名对象时进行投诉。对于纯数字的代理名称,情况并非如此,因为它们被解析为整数,随后会得到
为了使MySQL能够正确地将非数值解析为字符串文字,必须将它们引用为:
... 其中hrdis_或U.agency=',agency_名称,'。。。
^ ^
当然,如果代理机构名称包含“字符串引号字符”,则会出现问题。当然,任何此类事件都必须是。MySQL方便地提供了一个函数,正好用于此目的:
... 其中hrdis_或U.agency=,QUOTEagency_名称。。。
但是,为了防止可能的SQL注入攻击,您确实应该将准备好的语句参数化:
FETCH agency_cursor INTO @agency_name;
您不再需要申报机构名称;然后:
... 其中hrdis_或U.agency=?输入输出文件CONCAT'C:/HDD/'、?、.csv'。。。
其次是:
PREPARE s1 FROM @sql_text;
EXECUTE s1 USING @agency_name, @agency_name;
DEALLOCATE PREPARE s1;
请注意,您现在还可以在进入循环之前准备语句,并在循环中使用适当的值简单地执行它。这应该会产生轻微的性能改进。请记住在退出循环后取消分配
最后一点注意:您应该在FETCH命令之后立即检查exit_循环,否则您将尝试执行SELECT。。。当没有更多的代理机构时,最后一次进入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
谢谢这样做很好,节省了我几个小时的工作时间。我将尝试不使用准备好的语句。