【问题标题】:Woes using UPDATE with a CTE in MySQL (MariaDB)在 MySQL (MariaDB) 中使用带有 CTE 的 UPDATE 的问题
【发布时间】:2023-03-31 02:08:01
【问题描述】:

试图让 UPDATE 与 MySQL 中的 CTE 一起工作,我快疯了。

这是sa_general_journal 的简化架构:

CREATE TABLE `sa_general_journal` (
  `ID` int(10) unsigned NOT NULL AUTO_INCREMENT,
  `Transaction_ID` int(10) unsigned DEFAULT NULL COMMENT 'NULL if not split, same as ID for split records',
  `Date` timestamp NOT NULL DEFAULT current_timestamp(),
…
  `Statement_s` int(10) unsigned DEFAULT NULL,
…
  `Name` varchar(255) DEFAULT NULL,
…
  PRIMARY KEY (`ID`),
…
) ENGINE=InnoDB AUTO_INCREMENT=25929 DEFAULT CHARSET=utf8;

某些记录是“拆分的”,例如,信用卡对帐单金额可能包含拆分的销售税金额。在这种情况下,拆分记录的两个部分在 Transaction_ID 字段中具有相同的 ID。

批量导入记录时,不能引用last_insert_ID填写Transaction_ID字段,所以需要在后面清理这些。

这是我第一次天真的尝试,它说我在UPDATE 附近有一个错误。嗯嗯。

WITH cte AS (
    SELECT
        ID,
        MIN(ID) OVER(PARTITION BY `Date`, `Name`, Statement_s) AS Trans,
        Transaction_ID
    FROM sa_general_journal
    WHERE Transaction_ID = 0)
UPDATE cte
SET Transaction_ID = Trans

CTE 本身似乎有效,因为我可以使用 SELECT * FROM cte 跟踪它并得到我所期望的。

所以我开始搜索 StackOverflow,发现 CTE 不可更新,但您需要将它们加入到要更新的内容中。 “没问题!”我想,当我编写代码时:

WITH cte AS (
    SELECT
        ID,
        MIN(ID) OVER(PARTITION BY `Date`, `Name`, Statement_s) AS Trans,
        Transaction_ID
    FROM sa_general_journal
    WHERE Transaction_ID = 0)
UPDATE sa_general_journal gj, cte
SET gj.Transaction_ID = cte.Trans
WHERE gj.ID = cte.ID

没有快乐。同样的错误信息。

我的理解是,在 MySQL 中,您不需要列列表,但我也尝试使用列列表 (a, b, c),在 UPDATE 语句中引用了正确的列,但它仍然说我UPDATE附近有问题。

在互联网上使用UPDATEWITH 的例子非常少!我找到了一个,from Percona,这是我在上面尝试创建的,然后找到了另一个非常相似的示例 from MySQL itself

提前感谢您提供的任何帮助!

【问题讨论】:

  • 请在更新前后向您的问题添加示例数据。这将帮助您更快地得到答案。
  • 感谢您的建议。不幸的是,我不再有任何“之前”数据,这要感谢@Akina,他在下面提供了解决方案。

标签: mysql sql-update mariadb common-table-expression


【解决方案1】:

CTE 是子查询定义的一部分,而不是整个查询的一部分。查询必须在 CTE 之后指定。 CTE 不能单独使用。所以

UPDATE sa_general_journal gj
JOIN (WITH cte AS ( SELECT
                         ID,
                         MIN(ID) OVER(PARTITION BY `Date`, `Name`, Statement_s) AS Trans,
                         Transaction_ID
                    FROM sa_general_journal
                    WHERE Transaction_ID = 0)
      SELECT * FROM cte) subquery ON gj.ID = subquery.ID
SET gj.Transaction_ID = subquery.Trans

【讨论】:

  • 谢谢!我想我需要习惯于由内而外地思考!顺便说一句:我的查询基于 MySQL 团队建议的一个查询:bugs.mysql.com/bug.php?id=88397
  • 在查看您的解决方案时,我突然发现实际上根本不需要 CTE,是吗? cte 在您的解决方案中没有被引用。除了实际的SELECT 语句之外,我不能删除subquery 括号内的所有内容吗?不挑剔;只是想学习! :-)
  • @JanSteinman 在我看来,实际上根本不需要 CTE,是吗? 当然。答案的目的是说明操作方法,而不是解决问题。
  • “答案的目的是展示如何做,而不是解决问题。”不用担心。两者都做到了!我很大胆,只是运行了你的查询——知道我有备份。但是我的工程师现在想优化它。 :-)
猜你喜欢
  • 2022-10-16
  • 2012-05-08
  • 2023-04-04
  • 2018-07-08
  • 2014-06-07
  • 1970-01-01
  • 1970-01-01
  • 2017-01-02
  • 2017-04-26
相关资源
最近更新 更多