回答

收藏

在安全模式下删除mysql

技术问答 技术问答 85 人阅读 | 0 人回复 | 2023-09-13

我有一位表格讲师,我想删除工资范围在一定范围内的记录。一种直观的方式是这样的:
* \! q1 Y& m$ Y0 {- }. c% t, u8 edelete from instructor where salary between 13000 and 15000;" s" i6 \" o& V% u; X$ Y" d: c& W
但是,在安全模式下,如果不提供主键(ID),则无法删除记录。
( R# o% W' ?6 y/ ?) x1 `所以我写下面的sql:6 s! A6 S4 ^3 t6 O0 f
delete from instructor where ID in (select ID from instructor where salary between 13000 and 15000);* F& @- a' l) H2 Y- ^6 Q1 t9 {  D
但是,有一个错误:0 p+ X/ k( U2 P/ I: o
You can't specify target table 'instructor' for update in FROM clause5 a' l$ d& u# Z# J0 u" B" Z
我很困惑,因为当我写) Y; j2 B. Y! n' J- E
select * from instructor where ID in (select ID from instructor where salary between 13000 and 15000);( h& a% n2 ^! U5 s, h
它不会产生错误。
! ?" B  {5 \& P7 L/ \3 t我的问题是:# P7 W0 C! M# p
[ol]此错误消息的真正含义是什么,为什么我的代码是错误的?/ E' E/ u0 e$ o1 l
如何重写此代码以使其在安全模式下工作?
1 ^) v7 x" h& X( W6 ~9 D[/ol]
8 D! N: T1 D1 U谢谢!
6 P9 t9 s* P6 J: V               
+ D8 v0 ?2 h; |! p$ T8 u解决方案:
' y! i7 y0 b; `* ^' O               
% [* q; e( [! b" v+ _) b0 B! }8 E" ^* |) B5 H( m$ `4 M/ f
5 y* R" o$ @, Z0 C& G& p
                到处搜寻,最流行的答案似乎是“只关闭安全模式”:' \" d1 O$ a1 Q/ }" t" B* z' T) @
SET SQL_SAFE_UPDATES = 0;6 ^( J. q. A$ O; K' j& B
DELETE FROM instructor WHERE salary BETWEEN 13000 AND 15000;, {7 K* T/ C) M% F9 K* x% U
SET SQL_SAFE_UPDATES = 1;
& h6 ^) t- k# l6 j! g* q老实说,我不能说我曾经养成以安全模式运行的习惯。不过,我对这个答案并不完全满意,因为它只是假设您每次遇到问题时都应该更改数据库配置。
, C% Q# }9 X* v/ S% z# e因此,您的第二个查询离标记更近了,但是又遇到了另一个问题:MySQL对子查询施加了一些限制,其中之一是,您不能在从子查询中选择表时修改表。" z# K, U2 C- Z7 {
引用MySQL手册《子查询限制》:5 g* u# q% {* A1 m( o/ f& \$ ~4 `$ ~
7 q. E9 I$ m8 D4 |6 [5 j
通常,您不能修改表并在子查询中从同一表中选择。例如,此限制适用于以下形式的语句:5 N+ y, _4 O1 b4 l& j- U
DELETE FROM t WHERE ... (SELECT ... FROM t ...);
- Y$ O( v/ X; B8 |9 tUPDATE t ... WHERE col = (SELECT ... FROM t ...);3 ^( x9 J: v0 m, j- v
{INSERT|REPLACE} INTO t (SELECT ... FROM t ...);' g1 S5 o' |9 [" K
例外:如果对FROM子句中的已修改表使用子查询,则上述禁止条件不适用。例子:( ?! z' ^; R1 b/ K
UPDATE t ... WHERE col = (SELECT * FROM (SELECT ... FROM t...) AS _t  }  _/ Y; A$ X1 Q
…);
5 U9 B9 G7 e- S; a0 S1 f; H5 E此处,FROM子句中子查询的结果存储为临时表,因此,在更新到t时,已经选择了t中的相关行。6 N+ I% K6 H% L; y6 R- ?; u' A8 p
2 L6 y/ }; L0 M+ Q# e8 ^
最后一点就是您的答案。在临时表中选择目标ID,然后通过引用该表中的ID进行删除:
& A1 l$ k9 a6 |' ^6 l9 cDELETE FROM instructor WHERE id IN (
0 G, I7 [% N2 W6 f! B  SELECT temp.id FROM (# G6 O7 t+ O- e
    SELECT id FROM instructor WHERE salary BETWEEN 13000 AND 15000
* c1 K/ y4 b( Y  ) AS temp
8 s/ {2 w$ T/ b1 T);  Q- r8 I* `, O8 V
SQLFiddle演示。
分享到:
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则