【问题标题】:Using PL/SQL to update a table based on another tables使用 PL/SQL 根据另一个表更新一个表
【发布时间】:2022-01-12 22:00:48
【问题描述】:

所以我有这张桌子A

ENTITY_ID DOCUMENT_ID CREATE_DATE CAPITAL_STOCK
XX123456789 WQE 17.08.02 1000
XX123456789 AXC 18.12.05 1000
XX123456789 MKU 19.07.04 1000
... ... ... ...

这张表B

ENTITY_ID LCOMPANY_CODE
XX123456789 678
... ... ...

还有这张表C

LCOMPANY_CODE CHANGE_DATE CAPITAL_STOCK
678 17.01.01 2000
678 18.01.01 4000
678 18.06.01 6500
... ... ...

正如您在table C 中看到的,CAPITAL_STOCK 在特定日期更改为相同的LCOMPANY_CODE

我想用C.CAPITAL_STOCK 值更新A.CAPITAL_STOCK,但首先要注意几点:

  1. 我必须链接Table Atable C 的唯一方法是通过table B,我不能简单地从table C 更新到table A

  2. C.CHANGE_DATE 17.01.01 处,C.CAPITAL_STOCK 的值为 2000table A 的值为 1000。例如,在表的每一行中,只要找到A.CREATE_DATE 所在的行,在这种情况下,between 17.01.01 and 17.12.31A.CAPITAL_STOCK 必须有value = 2000。无论何时找到A.CREATE_DATE 所在的行,在18.01.01 and 18.05.31 之间,A.CAPITAL_STOCK 必须有value = 4000,在18.05.31 之后CAPITAL_STOCK 应该有6500 值。

进行此更新的最佳方式是什么?

我正在考虑使用 PL/SQL 块,将值提取到游标,然后使用 for 循环漫游 A 表中的所有记录并使用适当的值进行更新,但这是最简单的解决方案吗?更让我困惑的是A-C table链接,然后是更新问题……

【问题讨论】:

  • 您可以使用触发器来解决这个问题。这可能很容易
  • 你能说得更具体些吗?我怎样才能构造那个代码块?

标签: sql plsql


【解决方案1】:

使用标准更新语法需要一个相关的子查询,这需要保证只返回一个值。在以下查询中,使用FETCH FIRST 1 ROWS ONLY 获取输入记录的创建日期或之前的最新记录。

UPDATE
  table_a  a
SET
  capital_stock = (
    SELECT
      c.capital_stock
    FROM
      table_b   b
    INNER JOIN
      table_c   c
        ON c.lcompany_code  = b.lcompany_code
    WHERE
          b.entity_id    = a.entity_id
      AND c.change_date <= a.create_date
    ORDER BY
      c.change_date DESC
    FETCH
      FIRST 1 ROWS ONLY
  )

演示:https://dbfiddle.uk/?rdbms=oracle_21&fiddle=22a1bef758e1fa65b0ebdc64e908ccad

一个缺点是所有记录都会被更新,即使它们不需要 .

避免这种情况的一般方法是使用MERGE...

MERGE INTO
  table_a
USING
  (
    SELECT
      a.*,
      c.capital_stock   AS revised_capital_stock
    FROM
      table_a   a
    INNER JOIN
      table_b   b
        ON a.entity_id = b.entity_id
    CROSS APPLY
    (
      SELECT capital_stock
        FROM table_c
       WHERE change_date   <= a.create_date
         AND lcompany_code  = b.lcompany_code
    ORDER BY change_date DESC
       FETCH FIRST 1 ROWS ONLY
    )
      c
  )
    revision
      ON (    revision.entity_id   = table_a.entity_id
          AND revision.document_id = table_a.document_id
          AND revision.create_date = table_a.create_date
         )
WHEN
  MATCHED THEN UPDATE
    SET capital_stock = revision.revised_capital_stock
  WHERE
    capital_stock <> revision.revised_capital_stock

演示:https://dbfiddle.uk/?rdbms=oracle_21&fiddle=b00017ed2a1a1bbced3f81557b06eb0c

(在此演示中,我更改了一个起始值以证明行不会在不必要时更新;您可以看到它仅更新两行。)

【讨论】:

  • 感谢@MatBailie 发现错误,我删除了原来的答案。
  • 我正在运行脚本,完成后我会给出反馈
  • 我需要什么,谢谢
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2010-09-18
  • 2013-01-25
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多