如何按特定顺序从 select 中执行 Oracle SQL 更新?

Posted

技术标签:

【中文标题】如何按特定顺序从 select 中执行 Oracle SQL 更新?【英文标题】:How do I do an Oracle SQL update from select in a specific order? 【发布时间】:2019-04-05 20:10:09 【问题描述】:

我有一个表,其中包含旧值(一些为空)和各种属性的新值,所有这些都在整个月的不同添加时间插入。我正在尝试使用带有营业月结束日期的记录更新第二个表。目前,这些记录仅包含所有月末日期的最新值。目标是通过使用第一个表中的旧值更新上月末的值来创建历史数据。我是一个初学者,并且能够提出一个查询来更新一个对象,其中第一个表中有一个条目。现在我正在尝试扩展查询以包含多个对象,并且可能在同一个月内具有多个旧值。我尝试使用“order by”(因为我需要按升序进行一个月的更新,以便获得最新的值)但是读取它不适用于没有子查询的更新语句。所以我试着做一个更复杂的查询,但没有成功。我收到以下错误:单行子查询返回多行。谢谢!

表A:

| ID | TYPE | OLD_VALUE | NEW_VALUE | ADD_TIME|
-----------------------------------------------
| 1 | A     | 2 | 3 | 1/11/2019 8:00:00am |
| 1 | B     | 3 | 4 | 12/10/2018 8:00:00am|
| 1 | B     | 4 | 5 | 12/11/2018 8:00:00am|
| 2 | A     | 5 | 1 | 12/5/2018 08:00:00am|
| 2 | A     | 1 | 2 | 12/5/2019 09:00:00am|
| 2 | A     | 2 | 3 | 12/5/2019 10:00:00am|
| 2 | B     | 1 | 2 | 12/5/2019 10:00:00am|

表B

| ID | MONTH_END | TYPE_A | TYPE_B | 
-----------------------------------
| 1  | 1/31/19  | 3  | 5 |
| 1  | 12/31/18 | 3  | 5 |
| 1  | 11/30/18 | 3  | 5 |
| 2  | 12/31/18 | 3  | 2 |
| 2  | 11/30/18 | 3  | 2 |

TableB 的期望输出

| ID | MONTH_END | TYPE_A | TYPE_B | 
-----------------------------------
| 1  | 1/31/19  | 3  | 5 |
| 1  | 12/31/18 | 2  | 5 |
| 1  | 11/30/18 | 2  | 3 |
| 2  | 12/31/18 | 3  | 2 |
| 2  | 11/30/18 | 5  | 2 |

我的 A 型查询(我计划适应 B 型并执行所需的输出)

update TableB B
set b.type_a =
(
    with aa as
    (
    select id, nvl(old_value, new_value) typea, add_time
    from TableA 
    where type = 'A'
    order by id, add_time ascending
    )
select typea
from aa
where aa.id = b.id
and b.month_end <= aa.add_tm
)
where exists
(
    with aa as
    (
    select id, nvl(old_value, new_value) typea, add_time
    from TableA 
    where type = 'A'
    order by id, add_time ascending
    )
select typea
from aa
where aa.id = b.id
and b.month_end <= aa.add_tm
)

【问题讨论】:

SQL 是一种声明性语言,而不是过程性语言,因此事情发生的顺序无关紧要。事实上,重要的是它不这样做。您包含数据很好,但我无法弄清楚您如何从现有输出获得所需的输出。你能重述所涉及的规则吗? 【参考方案1】:

Kudo 用于提供示例输入数据和所需输出。我发现您的问题有点令人困惑,所以让我改写为“提供表 a 中与月底在同一月份的最后一个类型的值。

通过匹配输入类型和日期,我们可以得到您的答案。 “ROWNUM=1”是将结果集限制为单个条目,以防多行具有相同的 add_time。这个SQL还是一团糟,也许其他人能想出一个更好的。

UPDATE tableb b
   SET b.typea   =
           (SELECT old_value
              FROM tablea a
             WHERE     LAST_DAY( TRUNC( a.add_time ) ) = b.month_end
                   AND TYPE = 'A'
                   AND add_time =
                       (SELECT MAX( add_time )
                          FROM tablea
                         WHERE TYPE = 'A' AND LAST_DAY( TRUNC( a.add_time ) ) = b.month_end)
                   AND ROWNUM = 1)
 WHERE EXISTS
           (SELECT old_value
              FROM tablea a
             WHERE LAST_DAY( TRUNC( a.add_time ) ) = b.month_end AND TYPE = 'A');

【讨论】:

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

如何按特定顺序从列表中删除字符串而不输入其值? [复制]

如何从select2多选中的选项列表中删除选定的选项并按选择的顺序显示选定的选项

MySQL:按顺序插入选择

如何在 JUnit4 中按特定顺序运行测试方法?

如何强制使用 NSPredicate 从硬盘检索图像的特定顺序

列顺序很重要的 Oracle DB 简单 SELECT