考虑以下两个表:
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将:
Since this is version dependent,我想找到一个能满足#1的查询。
我想删除所有未被其他表引用的用户。
我已阅读this question,但我不想检查所有其他表格以查看是否引用了user_id。
如果我有很多很多桌子,这种方法不会起作用。
users
user_payments
user_info
user_keywords
user_logs
user_etc
...
所有user_ *表都可以引用一些用户(id)。
那么如何编写一个只删除未被任何其他表引用的用户的查询?
答案 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)进行循环,但我认为上面应该可以解决这个问题。