在安全模式下删除mysql


86

我有一位表讲师,我想删除工资范围在一定范围内的记录。一种直观的方式是这样的:

delete from instructor where salary between 13000 and 15000;

但是,在安全模式下,如果不提供主键(ID),则无法删除记录。

所以我写下面的sql:

delete from instructor where ID in (select ID from instructor where salary between 13000 and 15000);

但是,有一个错误:

You can't specify target table 'instructor' for update in FROM clause

我很困惑,因为当我写

select * from instructor where ID in (select ID from instructor where salary between 13000 and 15000);

它不会产生错误。

我的问题是:

  1. 此错误消息的真正含义是什么,为什么我的代码错误?
  2. 如何重写此代码以使其在安全模式下工作?

谢谢!


您要保持安全模式吗?并且您正在使用mySql工作台吗?
wribit

这两个问题的答案都是肯定的。而且令我惊讶的是,当我使用jdbc删除没有PK的mysql数据库中的记录时,它不会产生错误。那么安全模式仅适用于mysql工作台吗?
罗兰·罗

1
否-我在问,因为如果您想在mySQL工作台中将其关闭,我可以告诉您如何做。就我个人而言,我不使用它...必须拥有ID是非常安全的做法-但是从开发角度来看,我发现这样做很痛苦
wribit 2014年

Answers:


223

到处搜寻,流行的答案似乎是“只关闭安全模式”

SET SQL_SAFE_UPDATES = 0;
DELETE FROM instructor WHERE salary BETWEEN 13000 AND 15000;
SET SQL_SAFE_UPDATES = 1;

老实说,我不能说我曾经养成以安全模式运行的习惯。不过,我对这个答案并不完全满意,因为它只是假设您每次遇到问题时都应该更改数据库配置。

因此,您的第二个查询离标记更近了,但是又遇到了另一个问题:MySQL对子查询施加了一些限制,其中之一是您无法在子查询中从中选择表时修改表。

引用MySQL手册《子查询限制》

通常,您不能修改表并在子查询中从同一表中选择。例如,此限制适用于以下形式的语句:

DELETE FROM t WHERE ... (SELECT ... FROM t ...);
UPDATE t ... WHERE col = (SELECT ... FROM t ...);
{INSERT|REPLACE} INTO t (SELECT ... FROM t ...);

例外:如果对FROM子句中的已修改表使用子查询,则上述禁止条件不适用。例:

UPDATE t ... WHERE col = (SELECT * FROM (SELECT ... FROM t...) AS _t ...);

这里,FROM子句中子查询的结果存储为临时表,因此在更新到t时已经选择了t中的相关行。

最后一点就是您的答案。在临时表中选择目标ID,然后通过引用该表中的ID进行删除:

DELETE FROM instructor WHERE id IN (
  SELECT temp.id FROM (
    SELECT id FROM instructor WHERE salary BETWEEN 13000 AND 15000
  ) AS temp
);

SQLFiddle演示


6
谢谢您的解释!但是,我在mysql工作台中尝试了您的代码,但仍然显示“您正在使用安全更新模式,并且试图在不使用使用KEY列的WHERE的情况下更新表”。
罗兰·罗

真是出乎意料 主键是否使用其他名称?我注意到您的问题似乎表明它的名字ID,而我的答案使用id
rutter

是的,我将其更改为ID,但它不起作用。我尝试从讲师ID ='1'删除,并且它可以正常工作,因此ID是主键
roland luo 2014年

1
@rolandluo我知道已经很长时间了,但是我很好奇您是否找到了解决方法。显然,此方法在其他情况下也有效,所以我想知道为什么您的情况有所不同。可能是特定于您的服务器或版本的东西?
罗特2015年

19

您可以诱使MySQL认为您实际上是在指定主键列。这使您可以“替代”安全模式。

假设您有一个带有自动递增数字主键的表,则可以执行以下操作:

DELETE FROM tbl WHERE id <> 0

12

在Mysql工作台6.3.4.0中关闭安全模式

编辑菜单=>首选项=> SQL编辑器:其他部分:单击“安全更新” ...以取消选中该选项

工作台首选项


2
“如何重写此代码以使其在安全模式下工作?” ==>您的答案告诉您如何禁用安全模式;)
ByteHamster '16

2
抱歉,我完全误解了这个问题。当我无法使用Mysql工作台从表中删除时,我找到了这个主题,而在mysql工作台的注释中也有类似的问题,但是我无法创建注释。我认为,这将是在此处写下以供将来参考的好地方...
Peter B

0

我有一个简单得多的解决方案,它正在为我工​​作;这也是一种解决方法,但可能有用,您不必更改设置。我假设您可以使用永远不会存在的值,然后在WHERE子句中使用它

从MyTable删除WHERE MyField IS_NOT_EQUAL AnyValueNoItemOnMyFieldWillEverHave

我也不太喜欢这种解决方案,这就是为什么我在这里,但是它有效,而且似乎比已回答的要好

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.