我有一个存储过程来创建一个名册表。 Source是一个收集所需数据的视图。存储过程应准备要显示给团队的数据。对于特定团队成员或所有人的概述。当我第一次调用程序时,一切都很好,我按预期收到数据。但是在使用不同参数的第二次运行时,它会失败并出现错误' SQL错误[1042] [42S22] :( conn:218)未知列' d0294220.duties.TM 3'在'字段列表'查询是:调用somp_roster(' Ritchie')'
缺少的列取决于第一次运行中的参数。
该视图从4个表中收集数据:
CREATE VIEW somv_roster AS
SELECT bd.businessday AS Datum,
v.venue AS Dropzone,
d.duty AS Service,
c.nickname AS Staff
FROM som_roster r
INNER JOIN som_businessday bd ON bd.businessdayID = r.ID_businessday
INNER JOIN som_venue v ON v.venueID = bd.ID_venue
INNER JOIN som_duty d ON d.dutyID = r.ID_duty
INNER JOIN som_contact c ON c.contactID = r.ID_contact
ORDER BY bd.businessday, v.venue
WHERE bd.businessday >= CURDATE();
结果如下所示:
Datum Dropzone Service Staff
2018-04-28 Illertissen TM 2 Manu
2018-04-28 Illertissen Packer Martina B.
2018-04-28 Illertissen TM 1 Rued
2018-04-28 Illertissen TM 3 Hane
2018-04-29 Illertissen Manifest Sissi
2018-04-29 Illertissen TM 2 Ritchie
2018-04-29 Illertissen Packer Martina B.
2018-04-29 Illertissen TM 1 Rued
2018-04-29 Illertissen TM 3 Hane
2018-05-01 Illertissen TM 1 Ritchie
2018-05-01 Illertissen TM 3 Hane
2018-05-01 Illertissen TM 2 Purzl
2018-05-01 Illertissen Packer Martina B.
2018-05-26 Illertissen TM 1 Rued
2018-05-26 Kempten TM 1 Ritchie
2018-05-26 Kempten TM 2 Hane
2018-05-26 Kempten Manifest Sissi
现在我要建立一个新的表格来表明:
Datum Dropzone Manifest Packer TM 1 TM 2 TM 3
2018-04-28 Illertissen [NULL] Martina B. Rued Manu Hane
2018-04-29 Illertissen Sissi Martina B. Rued Ritchie Hane
2018-05-01 Illertissen [NULL] Martina B. Ritchie Purzl Hane
2018-05-26 Illertissen [NULL] [NULL] Rued [NULL] [NULL]
2018-05-26 Kempten Sissi [NULL] Ritchie Hane [NULL]
或者对于特定的团队成员,它应该如下所示:
Datum Dropzone TM 2 TM 3
2018-04-28 Illertissen [NULL] Hane
2018-04-29 Illertissen [NULL] Hane
2018-05-01 Illertissen [NULL] Hane
2018-05-26 Kempten Hane [NULL]
在存储过程中,我定义了一个游标并循环遍历该游标。在临时表中,我添加结果并在结尾显示表。
存储过程:
/*
* Create routine somp_roster()
* Requires somp_roster_et() to expand the columns dynamically.
* Requires somv_roster view to read the rosters.
* 4Air 2018 (c)
*/
DROP PROCEDURE IF EXISTS somp_roster;
DELIMITER $$
CREATE PROCEDURE somp_roster(IN staff_name VARCHAR(25))
BEGIN
/*
* variables have to be declared at the start of the procedure
* declare variables for the loops
* flag to be set at the end of the loop
*/
DECLARE finishedloop INTEGER DEFAULT 0;
-- flag to loop through the duty table to
DECLARE temp_date DATE DEFAULT NULL;
DECLARE temp_venue VARCHAR(25) DEFAULT '';
DECLARE temp_duty VARCHAR(25) DEFAULT '';
DECLARE temp_staff VARCHAR(25) DEFAULT '';
-- this var holds the string for the alter table statement
DECLARE alttable VARCHAR(250) DEFAULT '';
-- the first cursor to prepare the temp table
DECLARE roster_cursor CURSOR FOR
SELECT * FROM somv_roster WHERE Datum >= CURDATE() AND Staff LIKE CONCAT('%',staff_name) ORDER BY Service;
-- to recognize the end of the loops. Set to 0 before starting the loop!
DECLARE CONTINUE HANDLER FOR NOT FOUND SET finishedloop = 1;
-- cleanup first from a interrupted previous run
DROP TEMPORARY TABLE IF EXISTS duties;
-- now we need a temp table for the duties
CREATE TEMPORARY TABLE duties (Datum DATE, Dropzone VARCHAR(25), PRIMARY KEY(Datum, Dropzone)) ENGINE=MEMORY DEFAULT CHARSET=utf8 COLLATE=utf8_general_ci;
-- loop through the temp table
SET finishedloop = 0;
OPEN roster_cursor;
SET @alttable = '';
get_roster_loop: LOOP
-- now read the duties and create the new rows in the temp rosters
FETCH roster_cursor INTO temp_date, temp_venue, temp_duty, temp_staff;
IF finishedloop = 1 THEN
LEAVE get_roster_loop;
END IF;
/*
* fist step - try to expand the table with needed column
* the statement has to be this:
* call somp_rosters_et('tablename','columnname','columndefs')
* example:
* CALL somp_rosters_et('duties','TM 1','VARCHAR(25)');
*/
CALL somp_roster_et('duties',temp_duty,'VARCHAR(25)');
/*
* next prepare the statement to fill the data...
* implies the test if the date and venue already exists
* if so, then use UPDATE TABLE rather then INSERT TABLE
*/
SET @alttable = CONCAT('INSERT INTO duties (`Datum`,`Dropzone`,`', temp_duty , '`) VALUES (''' , temp_date , ''',''' , temp_venue , ''',''' , temp_staff , ''') ON DUPLICATE KEY UPDATE `', temp_duty , '` = ''', temp_staff , ''';') ;
PREPARE stmt FROM @alttable;
EXECUTE stmt;
DEALLOCATE PREPARE stmt;
END LOOP get_roster_loop;
CLOSE roster_cursor;
SELECT * FROM duties ORDER BY Datum, Dropzone;
DROP TEMPORARY TABLE IF EXISTS duties;
END $$
DELIMITER ;
将所需列添加到临时表的第二个存储过程: 当我尝试添加现有列时,我构建它以获得sql异常的第二个处理程序。
/*
* Stored Procedure to expand the table and do not care about an error if the column exists.
* Used by somp_roster();
* 4Air 2018 (c).
*/
DROP PROCEDURE IF EXISTS somp_roster_et;
DELIMITER $$
CREATE PROCEDURE somp_roster_et(IN t_name VARCHAR(25), IN c_name VARCHAR(25), IN c_attribute VARCHAR(25))
BEGIN
DECLARE eflag INTEGER DEFAULT 0;
DECLARE modtable VARCHAR(150) DEFAULT "";
DECLARE CONTINUE HANDLER FOR SQLEXCEPTION SET eflag = 1;
SET @modtable = CONCAT('ALTER TABLE ' , t_name , ' ADD COLUMN `' , c_name , '` ' , c_attribute , ';');
-- INSERT INTO som_log (Entry) VALUES(CONCAT('somp_roster_et: ',@modtable));
PREPARE stmt FROM @modtable;
EXECUTE stmt;
DEALLOCATE PREPARE stmt;
END $$
DELIMITER ;
这适用于第一次运行。在第二次运行时,使用不同的团队成员作为第一个过程的参数,过程结束时的SELECT语句将引发错误:
SQL错误[1054] [42S22] :( conn:218)未知栏' d0294220.duties.TM 3'在'字段列表'查询是:调用somp_roster(' Ritchie')
当我从过程中删除最后一个SELECT并删除drop table命令时,我可以手动接收数据:
call somp_roster('Ritchie');
SELECT * FROM duties;
call somp_roster('Martina B.');
SELECT * FROM duties;
这很好用。为什么在选择过程中的数据时会出现异常?
理查德
2018-DEC-04
仍在与此作斗争...我已经改变了程序,但奇怪的行为仍然存在。
新程序:
/*
* Create routine somp_roster()
*
* 2018-02-15 / implement a second handler for sql exceptions to handle the expand and select in this script
*
* somp_roster_et is depricated with this change.
*
* Requires somv_roster view to read the rosters.
* 4Air 2018 (c)
*/
DROP PROCEDURE IF EXISTS somp_roster;
DELIMITER $$
CREATE PROCEDURE somp_roster(IN staff_name VARCHAR(25))
BEGIN
/*
* variables have to be declared at the start of the procedure
* declare variables for the loops
* flag to be set at the end of the loop
*/
DECLARE finishedloop,eflag, loopcount INTEGER DEFAULT 0;
-- flag to loop through the duty table to
DECLARE temp_date DATE DEFAULT NULL;
DECLARE temp_venue, temp_duty, temp_staff VARCHAR(25) DEFAULT '';
-- this var holds the string for the alter table statement
DECLARE alttable,modtable VARCHAR(250) DEFAULT '';
-- the first cursor to prepare the temp table
DECLARE roster_cursor CURSOR FOR
SELECT * FROM somv_roster WHERE date >= CURDATE() AND staff LIKE CONCAT('%',staff_name) ORDER BY service;
-- to recognize the end of the loops. Set to 0 before starting the loop!
DECLARE CONTINUE HANDLER FOR NOT FOUND SET finishedloop = 1;
-- to recognize a sql exception and continue
DECLARE CONTINUE HANDLER FOR SQLEXCEPTION SET eflag = 1;
-- cleanup first from a interrupted previous run
DROP TEMPORARY TABLE IF EXISTS duties;
-- now we need a temp table for the duties
CREATE TEMPORARY TABLE duties (Datum DATE, Dropzone VARCHAR(25), PRIMARY KEY(Datum, Dropzone)) ENGINE=MEMORY DEFAULT CHARSET=utf8 COLLATE=utf8_general_ci;
-- loop through the temp table
SET finishedloop = 0;
OPEN roster_cursor;
SET @alttable = '';
get_roster_loop: LOOP
-- now read the duties and create the new rows in the temp rosters
FETCH roster_cursor INTO temp_date, temp_venue, temp_duty, temp_staff;
IF finishedloop = 1 THEN
LEAVE get_roster_loop;
END IF;
SET @modtable = CONCAT('ALTER TABLE duties ADD COLUMN `' , temp_duty , '` VARCHAR(25);');
PREPARE stmt FROM @modtable;
EXECUTE stmt;
DEALLOCATE PREPARE stmt;
/*
* next prepare the statement to fill the data...
* implies the test if the date and venue already exists
* if so, then use UPDATE TABLE rather then INSERT TABLE
*/
SET @alttable = CONCAT('INSERT INTO duties (`Datum`,`Dropzone`,`', temp_duty , '`) VALUES (''' , temp_date , ''',''' , temp_venue , ''',''' , temp_staff , ''') ON DUPLICATE KEY UPDATE `', temp_duty , '` = ''', temp_staff , ''';') ;
PREPARE stmt FROM @alttable;
EXECUTE stmt;
DEALLOCATE PREPARE stmt;
END LOOP get_roster_loop;
CLOSE roster_cursor;
SELECT * FROM duties ORDER BY Datum, Dropzone;
DROP TEMPORARY TABLE IF EXISTS duties;
END $$
DELIMITER ;
现在我将临时表更改为持久的INNODB表,以查看该过程创建的内容,这始终是我期望的结果。现在我将最后的SELECT语句更改为:
SELECT COUNT(*) FROM duties;
我总是得到正确的计数。
任何想法是什么原因造成的?
理查德