如何从 select 进行 Oracle SQL 更新?

Posted

技术标签:

【中文标题】如何从 select 进行 Oracle SQL 更新?【英文标题】:How do I do an Oracle SQL update from select? 【发布时间】:2019-04-04 14:11:53 【问题描述】:

我创建了一个查询,用于从另一个表更新一个表。该字段在给定日期按预期更新。问题是对于其他日期,我现在在我更新的列上获得 NULL 值。如何只为特定日期设置新值而不影响其他日期?

表 A:

| ID | VALUE |      ADD_TIME        |
-------------------------------------
| 1  | -5    |1/11/2019 10:45:11 am |

表 B:

|AS_OF_DATE| ID | VALUE |
-------------------------
|2/29/2019 | 1  |  -4   |
|1/31/2019 | 1  |  -4   |
|12/31/2018| 1  |  -4   |

期望的输出:

|AS_OF_DATE| ID | VALUE |
-------------------------
|2/29/2019 | 1  |  -4   |
|1/31/2019 | 1  |  -4   |
|12/31/2018| 1  |  -5   |

电流输出:

|AS_OF_DATE| ID | VALUE |
-------------------------
|2/29/2019 | 1  |       |
|1/31/2019 | 1  |       |
|12/31/2018| 1  |  -5   |

我的查询:

update TABLEB
set VALUE =
(
  select VALUE from TableA
  where ID = '1'
  and TABLEB.AS_OF_DATE < TABLEA.ADD_TIME
)

【问题讨论】:

TABLEA 只有一行?比简单的添加 WHERE b.AS_OF_DATE &lt; (select ADD_TIME from TABLEA) 到 UPDATE 请检查您的数据类型:2/29/2019无效日期;) 【参考方案1】:

您可以添加exists() 检查,这样不匹配的行就不会更新:

update TABLEB
set VALUE =
(
  select VALUE from TABLEA
  where ID = '1'
  and TABLEB.AS_OF_DATE < TABLEA.ADD_TIME
)
where exists
(
  select VALUE from TABLEA
  where ID = '1'
  and TABLEB.AS_OF_DATE < TABLEA.ADD_TIME
)

1 row updated.

select * from tableb;

AS_OF_DAT         ID      VALUE
--------- ---------- ----------
28-FEB-19          1         -4
31-JAN-19          1         -4
31-DEC-18          1         -5

我在您的示例数据中将 2/29/2019 更改为 2/28/2019...

假设您确实在两个表中都有多个 ID,因此请在第二列上关联 - 而不是 WHERE ID = '1'(可能应该是 WHERE ID = 1!)使用 WHERE TABLEB.ID = TABLEA.ID

您也可以使用合并而不是更新,例如:

merge into tableb b
using tablea a
on (a.id = b.id and b.as_of_date < a.add_time)
when matched then update set b.value = a.value;

merge into tableb b
using tablea a
on (a.id = b.id)
when matched then update set b.value = a.value
where b.as_of_date < a.add_time;

【讨论】:

谢谢!是的,我有多个 ID,并将对此进行更新。现在,我只是想让一个工作。我很感激:)【参考方案2】:

您的方法表明,ID 列是TABLEA主键

请检查这是不是真的,否则你应该注意以下结构:

set VALUE =
(
  select VALUE from Table A
  where ID = '1'
  and TABLE B.AS_OF_DATE < TABLE A.ADD_TIME
)

如果子查询返回多于一行,您将立即看到 ORA-01427: single-row subquery returns more than one row

对于支持TABLEA主键,您可以使用原始查询的简单扩展(添加WHERE 谓词):

update TABLEB 
set VALUE =
(
  select VALUE from TableA
  where ID = '1'
  and TABLEB.AS_OF_DATE < TABLEA.ADD_TIME
)
where TABLEB.AS_OF_DATE < (select ADD_TIME from TABLEA where ID = '1')

注意,重复行问题与其他答案中提出的MERGE 语句解决方案相关,该解决方案对于TABLEA 中的唯一ID 工作正常且优雅,但在重复ORA-30926: unable to get a stable set of rows in the source tables 上失败IDs .

【讨论】:

以上是关于如何从 select 进行 Oracle SQL 更新?的主要内容,如果未能解决你的问题,请参考以下文章

如何从 oracle pl sql 中的包主体内的 select 语句中捕获特定列

Oracle SQL If语句使用select进行比较[重复]

(SQL ORACLE)如何生成 html 输出,给定 select 语句?

oracle sql 基础:select 语句

查询oracle数据库时,如何定义变量进行查询

如何使用 oracle 从 sql 查询创建过程/函数?