我有两个表,一个基表包含有关值“tconst”(也是主键)的各种信息,另一个表在“titleId”名称下从“nconst”链接到多个“tconst”值'.
---基表'titlebasics'
tconst | 标题类型 | ... |
---|---|---|
tt0000009 | 电影 | ... |
tt0000147 | 电影 | ... |
... | ... | ... |
---额外信息表'knownfortitles'
id | nconst | 标题订单 | 标题ID |
---|---|---|---|
1 | nm0000001 | 1 | tt0050419 |
2 | nm0000001 | 2 | tt0053137 |
... | ... | ... | ... |
“问题”是 knownfortitles.titleId
中的某些值在 titlebasics.tconst
中不存在。我想创建一个存储过程,在其中可以将两个表和两个相应列的名称作为参数传递。此过程将首先检查第二个表中是否确实存在第一个表中不存在的值,如果是,则向第二个表添加一个名为 is_in_
的列。然后,它随后将使用第二个表中每一行的布尔值更新此列。我希望在存储过程中完成此操作,因为我有很多表都存在这个问题,并且我希望能够使用此过程,而不是使用不同的值一遍又一遍地编写相同的代码。但是,当我尝试调用我的程序时遇到错误,但我似乎无法修复该错误。
作为一个存储过程,这就是我陷入困境的地方。
CREATE PROCEDURE `CheckValueExistsInBaseTable`( IN checkedTable VARCHAR(100), IN referencedBaseTable VARCHAR(100), IN checkedCol VARCHAR(100), IN referencedCol VARCHAR(100) ) BEGIN DECLARE new_column_name VARCHAR(100) DEFAULT 'is_in_baseTable'; DECLARE sql_statement1 VARCHAR(1000) DEFAULT 'SELECT NULL;'; DECLARE sql_statement2 VARCHAR(1000) DEFAULT 'SELECT NULL;'; SET @new_column_name = CONCAT('is_in_',referencedBaseTable); -- Add new column to checked table if it doesn't exist SET @sql_statement1 = CONCAT('IF (SELECT CASE WHEN EXISTS( 选择1 FROM ', checkedTable, ' WHERE ', checkedCol, ' NOT IN (SELECT ', referencedCol, ' FROM ', referencedBaseTable, ')) THEN 1 ELSE 0 END ) = 1 THEN ALTER TABLE ', checkedTable, ' ADD ', @new_column_name, ' BOOL; ELSE SELECT NULL; END IF'); PREPARE stmt1 FROM @sql_statement1; EXECUTE stmt1; DEALLOCATE PREPARE stmt1; -- Update is_in_referencedBaseTable column in checked table SET @sql_statement2 = CONCAT('UPDATE ', checkedTable, ' SET ', @new_column_name, ' = CASE WHEN EXISTS(SELECT * FROM ', referencedBaseTable, ' WHERE ', referencedBaseTable, '.', referencedCol, ' = ', checkedTable, '.', checkedCol, ') THEN 1 ELSE 0 END'); PREPARE stmt2 FROM @sql_statement2; EXECUTE stmt2; DEALLOCATE PREPARE stmt2; END
无论我尝试更改什么,这都会给我带来以下错误之一。
错误代码:1064。您的 SQL 语法有错误;检查与您的 MySQL 服务器版本相对应的手册,了解在第 1 行“NULL”附近使用的正确语法
或
错误代码:1064。您的 SQL 语法有错误;检查与您的 MySQL 服务器版本相对应的手册,了解在 'IF (SELECT CASE WHEN EXISTS( 选择1 来自知名作品 WHERE titleId NOT' 在第 1 行
我还创建了测试程序来检查哪些部分可能出现问题,但两者都工作得很好,这让我更加困惑。第一个仅返回我在 CONCAT
中放入的内容,以查看其中是否存在任何语法错误。
创建过程`test`( 在 checkTable VARCHAR(100) 中, IN 引用的基表 VARCHAR(100), 在 checkCol VARCHAR(100) 中, IN ReferencedCol VARCHAR(100), IN new_column_name VARCHAR (100) ) 开始 -- 声明变量并赋值 声明 myvar VARCHAR(1000); DECLARE new_column_name VARCHAR(100) DEFAULT 'is_in_baseTable'; SET @new_column_name = CONCAT('is_in_',referencedBaseTable); SET myvar = CONCAT('IF (选择存在的情况( 选择1 FROM ', 已检查表, ' WHERE '、checkedCol、' NOT IN (SELECT '、referencedCol、' FROM '、referencedBaseTable、')) 然后 1 否则 0 结束 ) = 1 然后 ALTER TABLE ', checkTable, ' ADD ', @new_column_name, ' BOOL; 别的 选择空; 万一'); -- 将值打印到控制台 SELECT concat(myvar) AS 变量; 结束
此过程给出了一个结果:
IF (SELECT CASE WHEN EXISTS( 选择1 来自知名作品 WHERE titleId NOT IN(从 titlebasics 中选择 tconst)) 然后 1 否则 0 结束 ) = 1 然后 ALTER TABLEknownfortitles ADD is_in_titlebasics BOOL; 别的 选择空; END IF
可能的代码是正确的,我知道这一点是因为我使用了下面的第二个过程,该过程利用了这个恶意的代码块。
创建过程`test2`() 开始 IF(存在时选择案例( 选择1 来自知名作品 WHERE titleId NOT IN(从 titlebasics 中选择 tconst)) 然后 1 否则 0 结束 ) = 1 然后 ALTER TABLEknownfortitles ADD is_in_titlebasics BOOL; 别的 选择空; 万一; 结束
此过程将列is_in_titlebasics
添加到表knownfortitles
中,这就是我想要发生的事情,所以这很好。此时,我完全迷失了,不知道为什么我的实际存储过程不起作用,因为它基本上是最后两个过程的组合。我暂时忽略了我希望存储过程执行的第二部分,因为我遇到的错误似乎将第一个CONCAT
语句视为问题。
我希望这个问题非常明显,但我只是忽略了。欢迎任何帮助,提前致谢!
感谢 P. Salmon,我了解到问题是通过准备好的语句运行
IF ... THEN
语句。这不可能。经过一番修改后,我想出了以下程序,它的工作原理与我想要的完全一样。我希望我可以帮助一些与我遇到类似问题的人。但是,我想指出的是,我还没有添加
TRY ... CATCH
或任何阻止程序抛出错误的内容。这只是使其发挥作用的最低限度。调用过程
返回消息确认:
或消息警告:
仅在第一种情况下,才会根据需要添加
TINYINT(1)
列。