使用 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
,但首先要注意几点:
我必须 link Table A
和 table C
的唯一方法是 table B
,我不能简单地从 table C
到 table A
.
在 C.CHANGE_DATE 17.01.01
,C.CAPITAL_STOCK
的值为 2000
,在 table A
的值为 1000
。例如,在 table 的每一行中,每当找到 A.CREATE_DATE
的行时,在这种情况下,between 17.01.01 and 17.12.31
、A.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 table
link,然后更新问题...
使用标准更新语法需要相关的子查询,并且需要保证只返回一个值。在以下查询中,使用 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
(在这个演示中,我更改了一个起始值以演示如果不需要,行不会更新;您可以看到它只更新了两行。)
所以我有这个 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
,但首先要注意几点:
我必须 link
Table A
和table C
的唯一方法是table B
,我不能简单地从table C
到table A
.在
C.CHANGE_DATE 17.01.01
,C.CAPITAL_STOCK
的值为2000
,在table A
的值为1000
。例如,在 table 的每一行中,每当找到A.CREATE_DATE
的行时,在这种情况下,between 17.01.01 and 17.12.31
、A.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 table
link,然后更新问题...
使用标准更新语法需要相关的子查询,并且需要保证只返回一个值。在以下查询中,使用 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
(在这个演示中,我更改了一个起始值以演示如果不需要,行不会更新;您可以看到它只更新了两行。)