【问题标题】:Incorrect syntax near 'UPDATE''UPDATE' 附近的语法不正确
【发布时间】:2021-12-06 04:30:20
【问题描述】:

我有 2 张桌子 X 和 Y。

X 就像

D100_PTRSORID D100_LIB17 D100_LIB18 D100_LIB19 ....
10 15000 2000 75000 ...
11 12500 2500 7000 ...
12 ... ... ... ...
... ... ... ... ...

D100_LIBXX 字段中的金额不正确。我想通过表格 Y 更新这些金额,就像

GAD_PTRSORID GAD_CODE GAD_CAPITAL ... ....
10 201** 11000 ... ...
10 202** 1500 ... ...
10 203** 8500 ... ...
11 201** 12500 ... ...
... ... ... ... ...

D100_LIB17 与 GAD_CODE = '201**' 相关

D100_LIB18 与 GAD_CODE = '202**' 相关

D100_LIB19 与 GAD_CODE = '203**' 相关

我开始编写以下脚本来更新数据,但在“更新”级别(红色下划线)出现错误,并显示错误消息“更新”附近的语法不正确。预期的输入结束 - 或 - [...]

SELECT * FROM X

UPDATE Xx 
SET Xx.D100_LIB17=Yy.GAD_CAPITAL
FROM X Xx
INNER JOIN Y Yy 
ON Xx.D100_PTRSORID = Yy.GAD_PTRSORID and Yy.GAD_CODE = '201**'

SELECT * FROM X 

【问题讨论】:

  • 这好像是SQL,没有PL/SQL;如果这三个语句在一个脚本中,您实际上是否有语句分隔符(通常是分号)或它们之间的斜线? (您使用的客户端以及运行脚本的方式也可能会有所不同。)Oracle 也不允许 UPDATE ... FROM,但您可以使用相关更新。
  • @AlexPoole 你的意思是这段代码不适用于 PL/SQL 吗?我在互联网上查看了如何使用 PL/SQL 的 UPDATE 语句来编写这个脚本……我没有放“语句分隔符”。我是不是该 ?脚本的其余部分(创建表 X 和 Y 可以正常工作,无需分隔符)。您能否建议我一个可行的脚本?
  • 你没有展示脚本的其余部分,或者说你是如何(或在哪个客户端)运行它的。您可能单独运行创建语句,或者在它们后面加上斜杠。您的客户给出的模糊错误表明它认为更新是之前选择的一部分。

标签: oracle join sql-update


【解决方案1】:

错误可能是因为您没有终止单个语句;根据您的客户端和设置,通常使用分号语句分隔符来完成:

SELECT * FROM X;

UPDATE ... ;

SELECT * FROM X;

或斜线,单独一行(特别是对于 PL/SQL 块):

SELECT * FROM X
/

UPDATE ...
/

SELECT * FROM X
/

不过,您的更新语法对 Oracle 无效 - 您不能 UPDATE ... FROM 查询。您可以改用相关更新:

UPDATE X Xx
SET Xx.D100_LIB17 = (
  SELECT Yy.GAD_CAPITAL
  FROM Y Yy 
  WHERE Yy.GAD_PTRSORID = Xx.D100_PTRSORID
  AND Yy.GAD_CODE = '201**'
);

这将更新 X 中的所有行,而不仅仅是那些不同的行;如果您在 X 中有一行而在 Y 中没有匹配的行,则将设置为 null。

您也可以一次更新多个列,您可能需要考虑使用MERGE 而不是UPDATE,例如:

MERGE INTO X Xx
USING (
  SELECT GAD_PTRSORID,
    MAX(CASE GAD_CODE WHEN '201**' THEN GAD_CAPITAL END) AS D100_LIB17,
    MAX(CASE GAD_CODE WHEN '202**' THEN GAD_CAPITAL END) AS D100_LIB18,
    MAX(CASE GAD_CODE WHEN '203**' THEN GAD_CAPITAL END) AS D100_LIB19
  FROM Y
  GROUP BY GAD_PTRSORID
) Yy
ON (Yy.GAD_PTRSORID = Xx.D100_PTRSORID)
WHEN MATCHED THEN UPDATE SET
  Xx.D100_LIB17 = Yy.D100_LIB17,
  Xx.D100_LIB18 = Yy.D100_LIB18,
  Xx.D100_LIB19 = Yy.D100_LIB19;

db<>fiddle demo - 请注意,该演示中的两个值最终仍为 null,因为示例数据只有一行 ID 11。如果您始终拥有所有匹配的数据,这可能不是问题。如果你不这样做,那么你可以使用COALESCE() 来保留 Y 中没有对应值的列的现有值。

您可以扩展合并以插入缺失的行,其中您在 Y 中有 ID 而在 X 中没有匹配的行。或者将 X 定义为 Y 的透视视图,这样您就不必在两个位置维护相同的数据。

【讨论】:

  • 我几乎不再在 Oracle 中使用 UPDATE。 MERGE 在绝大多数情况下更合适。
  • @AlexPoole 我用您建议的 2 个脚本替换了我的脚本,但我收到一条新的错误消息 Oracle 数据库错误。表或视图不存在。你明白为什么了吗?
  • @Nassim - 您之前的评论表明这些表是在同一个脚本中创建的,因此您仍然需要这样做,如果这是一项任务并且在您开始之前它们不应该存在。或者,也许您没有将 X/Y 名称更改为您的真实表名。
  • 感谢 WITH 语句,我创建了 2 个名为 X 和 Y 的表。 WITH X AS (...) , Y as (...) SELECT * FROM X; 这部分工作正常。在这个脚本下面,我给你添加了一段代码。这是正确的做法吗?
  • @Nassim - WITH 不创建表;它是一个公用表表达式或子查询因式分解子句 (see the documentation),并被视为“作为内联视图或临时表”,仅在它所属的查询期间全部存在。尽管您可以在更新中使用 CTE,但尝试更新该子查询的结果是没有意义的。
猜你喜欢
  • 2015-12-12
  • 2013-12-16
  • 1970-01-01
  • 2020-07-11
  • 2018-08-14
  • 2011-03-11
  • 2014-02-16
  • 2017-01-11
  • 2020-02-06
相关资源
最近更新 更多