使用 PL/SQL 基于另一个 table 更新 table

Using PL/SQL to update a table based on another tables

所以我有这个 table 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
... ... ... ...

这个tableB

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

还有这个tableC

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. 我必须 link Table Atable C 的唯一方法是 table B,我不能简单地从 table Ctable A.

  2. C.CHANGE_DATE 17.01.01C.CAPITAL_STOCK 的值为 2000,在 table A 的值为 1000。例如,在 table 的每一行中,每当找到 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 table 中的所有记录并使用适当的值更新,但它是最简单的解决方案?更让我困惑的是A-C tablelink,然后更新问题...

使用标准更新语法需要相关的子查询,并且需要保证只返回一个值。在以下查询中,使用 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

(在这个演示中,我更改了一个起始值以演示如果不需要,行不会更新;您可以看到它只更新了两行。)