【问题标题】:On duplicate key gives Invalid token在重复键上给出无效的令牌
【发布时间】:2018-07-23 23:31:38
【问题描述】:

我正在尝试通过表clientref 中的cdclient 中的数字从employee_migration 更新name_code

 INSERT INTO employee_migration (name_code)
      Select cl.cdclient 
        From clientref cl 
  Inner Join employee_migration em  
          ON cl.client like upper(em.name)
          ON DUPLICATE KEY UPDATE name_code VALUES (cl.cdclient)

我收到此错误: 令牌无效。

Dynamic SQL Error.
SQL error code = -104.
Token unknown - line 3, column 1.
ON.

【问题讨论】:

  • select 内部工作正常。我得到了数字,但我必须在表格中更新它们
  • 为什么要在最后一行添加VALUES (cl.cdclient)
  • @lucumt,我在这里找到了一个例子:stackoverflow.com/questions/45366136/…
  • 可能是因为 'ON DUPLICATE' 出现在内部连接之后,您可以尝试在连接和重复连接之间放置一个“WHERE 1=1” for ex 吗?
  • 该错误不是 MySQL 错误,看起来您正在尝试在其他 DBMS 上执行 MySQL 语法查询

标签: sql firebird


【解决方案1】:

如果您使用 Firebird 服务器(没有说明,但从您的错误文本中可以看出),那么您可以使用 MERGE 命令。

但是,如果您使用 Interbase 服务器,那么我不知道您如何在那里编写该语句,请查阅 Interbase 手册:http://docwiki.embarcadero.com/InterBase/2017/en/Statement_and_Function_Reference_(Language_Reference_Guide)

您可以使用 Services -> Server Properties and Log 菜单在 IBExpert 中检查您使用的服务器。

假设您使用 Firebird 2.1 或更高版本

例如这样的:

MERGE INTO employee_migration dest
USING (
      Select cl.cdclient, em.ID
        From clientref cl 
  Inner Join employee_migration em  
          ON cl.client like upper(em.name)
      ) as src
ON dest.ID = src.ID -- or whatever your key columns are

WHEN MATCHED THEN UPDATE SET dest.namecode = src.cdclient

WHEN NOT MATCHED THEN INSERT (namecode, ID, ....)
    VALUES ( src.cdclient, ...., ...........)

但是,如果没有样本数据,您的请求似乎没有什么实际意义。

您的join 条件是cl.client like upper(em.name) - 这是“多对多”:对于clientref 中的每一行,employee_migration 中可以有许多对应的行,反之亦然。

因此,您可能会使用来自 src 查询的许多候选行来匹配和更新 employee_migration as dest 中的行。

  • 按照 SQL 标准,它应该会立即生成错误。
  • 通过 Firebird 2.x 实现 - 它会一个接一个地执行这些更新,覆盖以前的更新,并且只有最后一个候选行的结果才会保留。

【讨论】:

  • 我可以使用你写的代码吗?如果是,我有这个错误:列未知。 SRC.CLIENT。
  • 您必须了解我起草并完成的示例,因为我显然不知道您的表格及其列。更重要的是,我怀疑您的请求是否具有实际意义,因为它似乎会随机更新每一行,选择众多候选人中的一个......话虽如此,我的代码中没有SRC.CLIENT它。
  • 如果我创建两个小表:表 1(名称,代码 1)和表 2(名称,代码 2)。如何将table1中的code1复制到表2中的code2中。总的来说,我的意思是这个
  • 那么您可能在两个表中都有“名称”为PRIMARY KEY。好吧,首先您必须决定您打算如何处理 table1 中的值以及 table2 中缺少的名称?忽略它们,插入它们,将它们复制到 table3,等等。那必须决定。然后,如果你想匹配table1.name = table2.name 上的表格,那么这就是你必须做的。你从哪里得到的ON cl.client like upper(em.name)?为什么不cl.client = em.name?你知道UPPERLIKE 在那里做什么吗?他们引入“多对多”而不是“一对一”
  • 对于完全简化的示例table_source( ID, value )table_destination( ID, value ) 以及严格的匹配规则ID = ID,您可以通过文档或维基或任何谷歌搜索示例编写MERGE。只是你的问题看起来和那个“两张小桌子”的例子很不一样。
【解决方案2】:

Firebird 的语法与 MySQL 不同

MERGE INTO employee_migration
  USING (Select cl.cdclient 
    From clientref cl 
    Inner Join employee_migration em ON cl.client like upper(em.name)) AS tmp
  ON employee_migration.name_code = tmp.cdclient
  WHEN MATCHED THEN UPDATE SET name_code = tmp.cdclient
  WHEN NOT MATCHED THEN INSERT (name_code) VALUES(tmp.cdclient)

更新

正如@arioch-the 正确指出的那样,您需要MERGE command。我原来的解决方案实际上是错误的。

【讨论】:

  • 嗯,可能它适用于 VALUES() 并拒绝 SELECT ...然后你需要一个触发器来静默地将失败的 INSERT 转换为 UPDATE。
  • THEN INSERT (name_code) - 不行,您必须拥有 SQL INSERT 语句的所有列(自动生成或自动计算的除外)
  • 另一个技巧是使用EXECUTE BLOCK 来制作“匿名临时过程”,在那里你运行FOR SELECT 循环并为循环中的每一行执行UPDATE OR INSERT。虽然通常仍然更好地编写正确的合并。 firebirdsql.org/file/documentation/reference_manuals/… & firebirdsql.org/file/documentation/reference_manuals/…
  • 完全同意你的看法。我有一段时间没有使用 Firebird(我正在使用 Postgres),所以我一直想知道一些非常简单的东西是如何以如此复杂和不方便的方式制作出来的......
猜你喜欢
  • 2014-10-12
  • 2013-04-09
  • 1970-01-01
  • 2023-02-08
  • 2018-10-20
  • 2018-03-16
  • 2018-07-14
  • 2014-10-13
  • 2017-03-09
相关资源
最近更新 更多