【问题标题】:Error Code: 1093. You can't specify target table for update in FROM clause错误代码:1093。您不能在 FROM 子句中指定要更新的目标表
【发布时间】:2022-01-29 07:33:13
【问题描述】:

假设我有一个产品表并且只有 2 个字段; id 和购买日期。我想删除 2019 年购买的最后一个产品。 我尝试使用以下查询来做到这一点:

DELETE FROM products
WHERE id = (SELECT id
            FROM products
            WHERE purchase_date LIKE '2019%'
            ORDER BY purchase_date DESC
            LIMIT 1);

不幸的是,出现了标题中写的错误。我知道这个错误是一个已知错误,我已经尝试寻找解决方案。我查看了herehere,但是,我不明白如何更改我的查询以使其正常工作。

我很乐意得到帮助和解释。提前致谢。

【问题讨论】:

    标签: mysql sql sql-delete


    【解决方案1】:

    MySql 对于在子查询中也使用目标表的更新或删除语句是错误的。

    但您不需要子查询来使用 ORDER BYLIMIT

    DELETE FROM products
    WHERE YEAR(purchase_date) = 2019
    ORDER BY purchase_date DESC
    LIMIT 1;
    

    db小提琴here

    或者是sargable方式

    DELETE FROM products
    WHERE purchase_date >= '2019-01-01'
      AND purchase_date  < '2020-01-01'
    ORDER BY purchase_date DESC
    LIMIT 1;
    

    如果您仍然想使用查询? 然后愚弄MySql。 通过从查询或 CTE 中进行选择。

    WITH CTE_DELETE AS
    (
      SELECT id 
      FROM products 
      WHERE YEAR(purchase_date) = 2019
      ORDER BY purchase_date DESC
      LIMIT 1
    )
    DELETE FROM products t
    WHERE id IN (SELECT id FROM CTE_DELETE);
    
    DELETE FROM products t
    WHERE id IN (SELECT id FROM (
      SELECT id 
      FROM products 
      WHERE YEAR(purchase_date) = 2019
      ORDER BY purchase_date DESC
      LIMIT 1
    )d);
    

    【讨论】:

    • 我们不知道日期存储为 DATE TIME 列。这里有太多问题以 VARCHAR 列中的日期开头。无论如何,我看不出这如何解决 OP 报告的错误。
    • @TangentiallyPerpendicular 现在可以了。如果不是 DATE 列,WHERE YEAR(purchase_date) = 2019 也可以使用。
    • 好多了。反对票被赞成票取代 ?
    • @LukStorms 感谢您的回复。似乎 LIKE 确实适用于 DATE TIME 列。我确实将此列定义为 DATE TIME,而不是 VARCHAR。我不知道关键字 YEAR,现在很高兴知道。
    • 谢谢。事实上,人们可以在 MySql 中以某种方式喜欢一个日期。但这不是人们应该如何过滤它们的方式。
    【解决方案2】:

    试试这个

    DELETE FROM products
    WHERE id = (SELECT * FROM
                (SELECT id 
                FROM products
                WHERE purchase_date LIKE '2019%'
                ORDER BY purchase_date DESC
                LIMIT 1)tblTmp);
    

    查询基本相同,只是内部选择被包裹在另一个选择中。 需要注意的最重要的事情是原始选择已被赋予别名“tblTmp”。 (名称 tblTmp 是任意的,你可以给它任何别名。) 别名很重要,因为分配一个将告诉 MySQL 从这个选择查询创建一个临时表。 然后可以将临时表用作更新语句的源标准。 它被包装在另一个查询中的原因是,当它是更新语句的一部分时,MySQL 语法不允许您为选择查询分配别名。 所以我们必须把它放在另一个查询中,我想它将它与更新语句分开。

    【讨论】:

    • 感谢您的回答。它现在可以工作了!但是,我仍然对您的代码有疑问。我必须在第一个内部查询中使用 * 吗?别名 tblTmp 是否使 SQL 工作,因为它“认为”我不使用 products 表中的 SELECT?
    • 另外,不是需要在关键字FROM后面写一个表名吗?在您的建议中,FROM 子句后没有表,而是一行。
    • @Modern 查看更多详细信息dev.mysql.com/doc/refman/8.0/en/update.html。您不能使用同一张表,别名将其视为不同的表
    • @ErgestBasha 感谢您的回复。我知道我不能使用同一个表,但是,我不明白的是 SQL 如何允许给一行表一个表的别名并将其视为一个表?在这种情况下,(SELECT id FROM products WHERE purchase_date LIKE '2019%' ORDER BY purchase_date DESC LIMIT 1) 返回一行,但给出了一个表的别名。
    • @Modern 查询总是返回一个表,不管它是否是一行,它被视为一个表。 function 返回一个值
    猜你喜欢
    • 2018-11-15
    • 2018-10-25
    • 1970-01-01
    • 2014-01-29
    • 2014-07-31
    • 2012-07-29
    • 2013-04-09
    • 2021-08-15
    相关资源
    最近更新 更多