mysql错误1093-无法在from子句中指定更新的目标表

bwitn5fc  于 2021-06-21  发布在  Mysql
关注(0)|答案(16)|浏览(608)

我有一张table story_category 在我的数据库中有损坏的条目。下一个查询返回损坏的条目:

SELECT * 
FROM  story_category 
WHERE category_id NOT IN (
    SELECT DISTINCT category.id 
    FROM category INNER JOIN 
       story_category ON category_id=category.id);

我试图删除它们:

DELETE FROM story_category 
WHERE category_id NOT IN (
    SELECT DISTINCT category.id 
    FROM category 
      INNER JOIN story_category ON category_id=category.id);

但我得到了下一个错误:

1093-不能在from子句中指定更新的目标表'story\u category'

我怎样才能克服这个问题?

wfauudbj

wfauudbj1#

这个问题怎么样?希望有帮助

DELETE FROM story_category LEFT JOIN (SELECT category.id FROM category) cat ON story_category.id = cat.id WHERE cat.id IS NULL
3phpmpom

3phpmpom2#

根据@cheekysoft链接的mysql更新语法,它在底部写着。
当前,无法更新表并从子查询中的同一表中进行选择。
我猜您正在从商店类别中删除,同时仍在联盟中从中进行选择。

lxkprmvk

lxkprmvk3#

对于op试图实现的特定查询,理想且最有效的方法是根本不使用子查询。
这是你的名字 LEFT JOIN op两个查询的版本:

SELECT s.* 
FROM story_category s 
LEFT JOIN category c 
ON c.id=s.category_id 
WHERE c.id IS NULL;

注: DELETE s 将删除操作限制为 story_category table。
文档

DELETE s 
FROM story_category s 
LEFT JOIN category c 
ON c.id=s.category_id 
WHERE c.id IS NULL;
efzxgjgh

efzxgjgh4#

这个 inner join 在您的子查询中是不必要的。您似乎要删除中的条目 story_category 在哪里 category_id 不在 category table。
请执行以下操作:

DELETE FROM story_category 
WHERE category_id NOT IN (
    SELECT DISTINCT category.id 
    FROM category);

相反:

DELETE FROM story_category 
WHERE category_id NOT IN (
    SELECT DISTINCT category.id 
    FROM category INNER JOIN
         story_category ON category_id=category.id);
nnvyjq4y

nnvyjq4y5#

如果你做不到

UPDATE table SET a=value WHERE x IN
    (SELECT x FROM table WHERE condition);

因为它是同一张table,所以你可以忽悠和做:

UPDATE table SET a=value WHERE x IN
    (SELECT * FROM (SELECT x FROM table WHERE condition) as t)

[更新或删除或其他]

epfja78i

epfja78i6#

DELETE FROM story_category
WHERE category_id NOT IN (
    SELECT cid FROM (
        SELECT DISTINCT category.id AS cid FROM category INNER JOIN story_category ON category_id=category.id
    ) AS c
)
mwyxok5s

mwyxok5s7#

尝试将select语句的结果保存在单独的变量中,然后将其用于delete查询。

jfewjypa

jfewjypa8#

至于关注点,您希望删除中的行 story_category 不存在于 category .
以下是用于标识要删除的行的原始查询:

SELECT * 
FROM  story_category 
WHERE category_id NOT IN (
    SELECT DISTINCT category.id 
    FROM category INNER JOIN 
       story_category ON category_id=category.id
);

结合 NOT IN 子查询 JOIN 原来的表格似乎很复杂。这可以用更直截了当的方式来表达 not exists 以及相关子查询:

select sc.*
from story_category sc
where not exists (select 1 from category c where c.id = sc.category_id);

现在很容易把它变成一个 delete 声明:

delete from story_category
where not exists (select 1 from category c where c.id = story_category.category_id);

这个query可以在任何mysql版本上运行,也可以在我所知道的大多数其他数据库中运行。
db小提琴演示:

-- set-up
create table story_category(category_id int);
create table category (id int);
insert into story_category values (1), (2), (3), (4), (5);
insert into category values (4), (5), (6), (7);

-- your original query to identify offending rows
SELECT * 
FROM  story_category 
WHERE category_id NOT IN (
    SELECT DISTINCT category.id 
    FROM category INNER JOIN 
       story_category ON category_id=category.id);
| category_id |
| ----------: |
|           1 |
|           2 |
|           3 |
-- a functionally-equivalent, simpler query for this
select sc.*
from story_category sc
where not exists (select 1 from category c where c.id = sc.category_id)
| category_id |
| ----------: |
|           1 |
|           2 |
|           3 |
-- the delete query
delete from story_category
where not exists (select 1 from category c where c.id = story_category.category_id);

-- outcome
select * from story_category;
| category_id |
| ----------: |
|           4 |
|           5 |
pcrecxhr

pcrecxhr9#

更新:这个答案涵盖了一般错误分类。有关如何最好地处理op的确切查询的更具体的答案,请参阅此问题的其他答案
在mysql中,不能修改select部分中使用的同一个表。
此行为记录在:http://dev.mysql.com/doc/refman/5.6/en/update.html
也许你可以把table连起来
如果逻辑足够简单,可以重新调整查询的形状,则会丢失子查询并使用适当的选择条件将表连接到自身。这将导致mysql将表视为两个不同的东西,从而允许进行破坏性的更改。

UPDATE tbl AS a
INNER JOIN tbl AS b ON ....
SET a.col = b.col

或者,尝试将子查询嵌套到from子句中。。。
如果您确实需要子查询,那么有一个解决方法,但是它有几个原因,包括性能:

UPDATE tbl SET col = (
  SELECT ... FROM (SELECT.... FROM) AS x);

from子句中的嵌套子查询创建了一个隐式临时表,因此它不算作您正在更新的同一个表。
... 但要注意查询优化程序
但是,请注意,从MySQL5.7.6及更高版本开始,优化程序可能会优化子查询,但仍然会给出错误。幸运的是 optimizer_switch 变量可以用来关闭这种行为;尽管我不建议这样做仅仅是一个短期的解决方案,或者是一个小的一次性任务。

SET optimizer_switch = 'derived_merge=off';

多亏了彼得五世。米ørch在评论中对此建议表示感谢。
示例技术来自baron schwartz,最初发表在nabble,在这里进行了解释和扩展。

xe55xuns

xe55xuns10#

试试这个

DELETE FROM story_category 
WHERE category_id NOT IN (
SELECT DISTINCT category.id 
FROM (SELECT * FROM STORY_CATEGORY) sc;
ncgqoxb0

ncgqoxb011#

nexusrex为从同一个表中删除with join提供了一个非常好的解决方案。
如果您这样做:

DELETE FROM story_category
WHERE category_id NOT IN (
        SELECT DISTINCT category.id AS cid FROM category 
        INNER JOIN story_category ON category_id=category.id
)

你会得到一个错误。
但如果将条件 Package 在一个或多个选择中:

DELETE FROM story_category
WHERE category_id NOT IN (
    SELECT cid FROM (
        SELECT DISTINCT category.id AS cid FROM category 
        INNER JOIN story_category ON category_id=category.id
    ) AS c
)

它会做正确的事!!
说明:查询优化器对第一个查询执行派生合并优化(这会导致查询失败并出现错误),但第二个查询不符合派生合并优化的条件。因此优化器必须首先执行子查询。

wmvff8tz

wmvff8tz12#

最简单的方法是在子查询中引用父查询表时使用表别名。
例子:

insert into xxx_tab (trans_id) values ((select max(trans_id)+1 from xxx_tab));

更改为:

insert into xxx_tab (trans_id) values ((select max(P.trans_id)+1 from xxx_tab P));
hec6srdp

hec6srdp13#

如果有东西不起作用,从前门进来时,从后门进来:

drop table if exists apples;
create table if not exists apples(variety char(10) primary key, price int);

insert into apples values('fuji', 5), ('gala', 6);

drop table if exists apples_new;
create table if not exists apples_new like apples;
insert into apples_new select * from apples;

update apples_new
    set price = (select price from apples where variety = 'gala')
    where variety = 'fuji';
rename table apples to apples_orig;
rename table apples_new to apples;
drop table apples_orig;

很快。数据越大越好。

p1iqtdky

p1iqtdky14#

最近我不得不更新同一个表中的记录,我的做法如下:

UPDATE skills AS s, (SELECT id  FROM skills WHERE type = 'Programming') AS p
SET s.type = 'Development' 
WHERE s.id = p.id;
o4tp2gmn

o4tp2gmn15#

您可以将所需行的id插入临时表,然后删除该表中找到的所有行。
这可能就是@cheekysoft所说的分两步完成的意思。

相关问题