删除记录前需要检查表是否存在

GTE*_*GTE 7 mysql query error-handling

我的 Ruby 应用程序中有以下 SQL 查询:

sql = "DELETE FROM `#{database}`.`table1` WHERE `same_id` = #{some_id};"
Run Code Online (Sandbox Code Playgroud)

问题是在极少数情况下table1可能不存在。我需要构造这个查询,所以即使表不存在 SQL 也不会抛出错误。

我该如何实施?

Rol*_*DBA 8

您可能应该使用存储过程来执行此操作:

DELIMITER $$ 

DROP PROCEDURE IF EXISTS `test`.`DeleteByID` $$ 
CREATE PROCEDURE `test`.`DeleteByID` (db VARCHAR(64),tb VARCHAR(64),id_to_delete INT) 
BEGIN 
    DECLARE FoundCount INT;

    SELECT COUNT(1) INTO FoundCount
    FROM information_schema.tables
    WHERE table_schema = db
    AND table_name = tb;

    IF FoundCount = 1 THEN
        SET @sql = CONCAT('DELETE FROM ',db,'.',tb,' WHERE id=',id_to_delete); 
        PREPARE stmt FROM @sql; 
        EXECUTE stmt; 
        DEALLOCATE PREPARE stmt;
    END IF;

END $$ 

DELIMITER ; 
Run Code Online (Sandbox Code Playgroud)

您在代码中所做的就是调用存储过程。例如,要从 中删除 ID 128 drupaldb.comments

CALL test.DeleteByID('drupaldb','comments',128);
Run Code Online (Sandbox Code Playgroud)

试一试 !!!

另一个变化是直接雕刻查询:

set @given_db = 'drupaldb';
set @given_tb = 'comments';
set @given_id = 128;
set @good_sql = CONCAT('DELETE FROM ',@given_db,'.',@given_tb,' WHERE id=',@given_id);
set @evil_sql = 'SELECT 1';
SELECT IF(table_exists=1,@good_sql,@evil_sql) INTO @DeleteSQL
FROM
(
    SELECT COUNT(1) table_exists
    FROM information_schema.tables 
    WHERE table_schema=@given_db
    AND table_name=@given_tb
) A;
PREPARE stmt FROM @DeleteSQL; EXECUTE stmt; DEALLOCATE PREPARE stmt;
Run Code Online (Sandbox Code Playgroud)

注意:如果该表不存在,则执行的查询是SELECT 1

这是一个示例,显示该表是否不存在:

mysql>     set @given_db = 'drupaldb';
Query OK, 0 rows affected (0.00 sec)

mysql>     set @given_tb = 'comments';
Query OK, 0 rows affected (0.00 sec)

mysql>     set @given_id = 128;
Query OK, 0 rows affected (0.00 sec)

mysql>     set @good_sql = CONCAT('DELETE FROM ',@given_db,'.',@given_tb,' WHERE id=',@given_id);
Query OK, 0 rows affected (0.00 sec)

mysql>     set @evil_sql = 'SELECT 1';
Query OK, 0 rows affected (0.00 sec)

mysql>     SELECT IF(table_exists=1,@good_sql,@evil_sql) INTO @DeleteSQL
    ->     FROM
    ->     (
    ->         SELECT COUNT(1) table_exists
    ->         FROM information_schema.tables
    ->         WHERE table_schema=@given_db
    ->         AND table_name=@given_tb
    ->     ) A;
Query OK, 1 row affected (0.00 sec)

mysql>     PREPARE stmt FROM @DeleteSQL; EXECUTE stmt; DEALLOCATE PREPARE stmt;
Query OK, 0 rows affected (0.00 sec)
Statement prepared

+---+
| 1 |
+---+
| 1 |
+---+
1 row in set (0.00 sec)

Query OK, 0 rows affected (0.00 sec)

mysql>
Run Code Online (Sandbox Code Playgroud)

现在,这是表存在的示例:

mysql> select count(1) from mysql.user where user='rolando';
+----------+
| count(1) |
+----------+
|        0 |
+----------+
1 row in set (0.00 sec)

mysql> grant all on *.* to 'rolando'@'127.0.0.1';
Query OK, 0 rows affected (0.00 sec)

mysql> select count(1) from mysql.user where user='rolando';
+----------+
| count(1) |
+----------+
|        1 |
+----------+
1 row in set (0.00 sec)

mysql> set @given_db = 'mysql';
Query OK, 0 rows affected (0.00 sec)

mysql> set @given_tb = 'user';
Query OK, 0 rows affected (0.00 sec)

mysql> set @given_id = 'rolando';
Query OK, 0 rows affected (0.00 sec)

mysql> set @good_sql = CONCAT('DELETE FROM ',@given_db,'.',@given_tb,' WHERE user=''',@given_id,'''');
Query OK, 0 rows affected (0.00 sec)

mysql> set @evil_sql = 'SELECT 1';
Query OK, 0 rows affected (0.00 sec)

mysql> SELECT IF(table_exists=1,@good_sql,@evil_sql) INTO @DeleteSQL
    -> FROM
    -> (
    ->     SELECT COUNT(1) table_exists
    ->     FROM information_schema.tables
    ->     WHERE table_schema=@given_db
    ->     AND table_name=@given_tb
    -> ) A;
Query OK, 1 row affected (0.00 sec)

mysql> PREPARE stmt FROM @DeleteSQL; EXECUTE stmt; DEALLOCATE PREPARE stmt;
Query OK, 0 rows affected (0.02 sec)
Statement prepared

Query OK, 1 row affected (0.00 sec)

Query OK, 0 rows affected (0.00 sec)

mysql> select count(1) from mysql.user where user='rolando';
+----------+
| count(1) |
+----------+
|        0 |
+----------+
1 row in set (0.00 sec)

mysql>
Run Code Online (Sandbox Code Playgroud)


Mik*_*ll' 4

根据文档,IGNORE 选项会将错误视为警告。

DELETE IGNORE ...
Run Code Online (Sandbox Code Playgroud)

IGNORE关键字使MySQL忽略删除行过程中的所有错误。(解析阶段遇到的错误将以通常的方式处理。)由于使用 IGNORE 而被忽略的错误将作为警告返回。

我不确定MySQL是否会将不存在的表视为“解析阶段的错误”。如果是,您可以在information_schema中查询表名。沿着这些思路的东西应该有效。

SELECT table_name
FROM information_schema.tables
WHERE table_schema = 'your database name'
AND table_name = 'your table name';
Run Code Online (Sandbox Code Playgroud)

临时表不会出现在 information_schema 视图中。如果您的表是临时表,则代码中存在错误。你还没用完桌子就已经把它扔掉了。

  • 你不能用一句话来做到这一点。为什么不想在 Ruby 中处理错误?(在 Ruby 中*不*处理错误是没有意义的。) (2认同)