删除忽略在不同版本上的行为方式不同

时间:2018-03-20 05:29:17

标签: mysql

考虑以下两个表:

Users
------
id | name
1  | David
2  | John
3  | Sam

User_Payments
-----
id | user_id | amount
1  | 1       | 100
2  | 2       | 200

User_Payments.user_id REFERENCES Users(id) ON DELETE NO ACTION

^这意味着可能不会删除user_payments中引用的用户。

如果我们运行查询:

DELETE IGNORE FROM Users;

根据版本的不同,MySQL将:

  1. 删除Sam,因为他是唯一可以安全删除的用户
  2. 点击错误,但不会删除任何内容
  3. Since this is version dependent,我想找到一个能满足#1的查询。

    我想删除所有未被其他表引用的用户。

    我已阅读this question,但我不想检查所有其他表格以查看是否引用了user_id。

    如果我有很多很多桌子,这种方法不会起作用。

    users
    user_payments
    user_info
    user_keywords
    user_logs
    user_etc
    ...
    

    所有user_ *表都可以引用一些用户(id)。

    那么如何编写一个只删除未被任何其他表引用的用户的查询?

1 个答案:

答案 0 :(得分:0)

编辑3 :这可能有所帮助:

DELETE FROM Users WHERE

SELECT CONCAT('Users.id NOT EXISTS (SELECT ', t.table_name, '.user_id FROM t WHERE ', t.table_name, '.user_id=Users.id) AND')
FROM information_schema.tables t
WHERE t.table_name LIKE 'user\_%'
AND t.table_schema = 'ENTER_DB_NAME_HERE'
INTO OUTFILE '/tmp/sqlstatement.sql';

然后(滚动眼睛,对不起),连接后,删除训练AND并附加分号。

编辑2 :以下是经过修订的,可能是非常昂贵的建议:

DELETE IGNORE FROM Users

SELECT CONCAT('LEFT JOIN ', t.table_name, ' ON ', t.table_name, '.user_id=Users.id')
FROM information_schema.tables t
WHERE t.table_name LIKE 'user\_%'
AND t.table_schema = 'ENTER_DB_NAME_HERE'
INTO OUTFILE '/tmp/sqlstatement.sql';

WHERE

SELECT CONCAT(t.table_name, '.user_id IS NULL AND')
FROM information_schema.tables t
WHERE t.table_name LIKE 'user\_%'
AND t.table_schema = 'ENTER_DB_NAME_HERE'
INTO OUTFILE '/tmp/sqlstatement2.sql';

您必须手动将这些连接在一起。必须有一个更好的方法,抱歉垃圾邮件。

编辑:很抱歉,我发现这不起作用,因为您需要检查所有每个user_id的表格。

好吧,您可以使用创建存储过程,使用动态SQL和一堆CONCAT和循环,但是,看看this post,我认为以下内容可能会让您正确(和最安全)的轨道:

SELECT CONCAT('DELETE IGNORE FROM Users LEFT JOIN ', t.table_name, ' ON ', t.table_name, '.user_id=Users.id WHERE ', t.table_name, '.user_id IS NULL;')
FROM information_schema.tables t
WHERE t.table_name LIKE 'user\_%'
AND t.table_schema = 'ENTER_DB_NAME_HERE'
INTO OUTFILE '/tmp/sqlstatements.sql';

然后:

SOURCE /tmp/sqlstatements.sql;

执行(但先检查文件内容)。我没有对上述内容进行过测试,道歉,但希望它至少会有所帮助。比存储过程容易得多。另一种方法是用另一种语言(例如Python)进行循环,但我认为上面应该可以解决这个问题。