如何重写此 MySQL 查询,使其不会引发此错误:您无法在 FROM 子句中指定目标表 'crawlLog' 进行更新?
Posted
技术标签:
【中文标题】如何重写此 MySQL 查询,使其不会引发此错误:您无法在 FROM 子句中指定目标表 \'crawlLog\' 进行更新?【英文标题】:How do I rewrite this MySQL query so it doesn't throw this error: You can't specify target table 'crawlLog' for update in FROM clause?如何重写此 MySQL 查询,使其不会引发此错误:您无法在 FROM 子句中指定目标表 'crawlLog' 进行更新? 【发布时间】:2011-10-01 14:25:32 【问题描述】:我正在尝试从公司表中获取一个 ID,但该 ID 尚未在 crawlLog 表中。然后我需要将该 companyId 插入到 crawlLog 表中。
我需要在一次调用中执行此操作,以便并行爬虫在其他爬虫选择了一个 url 但尚未将其插入爬虫日志后不会拉取相同的 url。我不想因为产生其他问题而锁定表。
我从以下两个查询中都得到了这个错误:
You can't specify target table 'crawlLog' for update in FROM clause
这是我尝试做同样事情的两个查询。
INSERT INTO crawlLog (companyId, timeStartCrawling)
VALUES
(
(
SELECT companies.id FROM companies
LEFT OUTER JOIN crawlLog
ON companies.id = crawlLog.companyId
WHERE crawlLog.companyId IS NULL
LIMIT 1
),
now()
)
我也试过这个,但得到同样的错误:
INSERT INTO crawlLog (companyId, timeStartCrawling)
VALUES
(
(
SELECT id
FROM companies
WHERE id NOT IN
(
SELECT companyId
FROM crawlLog
)
LIMIT 1
),
now()
)
【问题讨论】:
这只能通过事务和一些锁定可靠地完成。如果你在 InnoDB 上,至少它只是一个行级锁而不是整个表锁。 您是否尝试为内部 crawlLog 设置别名? @Tocco - 你就是男人!!!做到了。这是一个绝妙的技巧。 嘿 .. 将此标记为精彩评论! 【参考方案1】:为什么要使用子选择? INSERT INTO ... SELECT 存在:
INSERT INTO crawlLog (companyId, timeStartCrawling)
SELECT companies.id, NOW()
FROM companies
LEFT OUTER JOIN crawlLog
ON companies.id = crawlLog.companyId
WHERE crawlLog.companyId IS NULL
LIMIT 1
这样它就不应该抱怨在 INSERT 和 SELECT 部分都使用表
【讨论】:
【参考方案2】:You can't update rows which you are querying。有一种方法可以强制 mysql 隐式使用临时表:
INSERT INTO crawlLog (companyId, timeStartCrawling)
VALUES
(
SELECT id, when FROM
(
SELECT companies.id AS id, now() AS when FROM companies
LEFT OUTER JOIN crawlLog
ON companies.id = crawlLog.companyId
WHERE crawlLog.companyId IS NULL
LIMIT 1
)
)
【讨论】:
【参考方案3】:这很有效,似乎是最简单的解决方案:
使用我的问题中两个语句中较简单的一个,我按照 @Tocco 在 cmets 中的建议为内部 crawlLog 表创建了一个别名,然后在 VALUES() 中删除了必要的封装。
INSERT INTO crawlLog (companyId, timeStartCrawling)
SELECT id, now()
FROM companies
WHERE id NOT IN
(
SELECT companyId
FROM crawlLog AS crawlLogAlias
)
LIMIT 1
【讨论】:
不确定是否有问题,但在 VALUES 中放置 SELECT 似乎很奇怪(不必要)。【参考方案4】:在临时表中进行选择,然后从临时表中插入选择。你不能在同一个语句中插入一个表并从中选择,所以使用一个临时表和两个语句。
【讨论】:
以上是关于如何重写此 MySQL 查询,使其不会引发此错误:您无法在 FROM 子句中指定目标表 'crawlLog' 进行更新?的主要内容,如果未能解决你的问题,请参考以下文章