使用子查询 (Oracle) 更新表

Posted

技术标签:

【中文标题】使用子查询 (Oracle) 更新表【英文标题】:Update of a table using subquery (Oracle) 【发布时间】:2019-10-21 18:17:21 【问题描述】:

我的表结构如下:

    HID            TIME_FROM         LAG_TIME_FROM          TIME_UNTIL
-------------------------------------------------------------------------
AAAAA12334566   06.07.19 04:04:51   13.07.19 04:05:17   13.07.19 04:05:17
AAAAA12334566   13.07.19 04:05:17   14.07.19 04:05:30   14.07.19 04:05:30
AAAAA12334566   14.07.19 04:05:30   23.07.19 22:00:00   23.07.19 22:00:00
AAAAA12334566   23.07.19 22:00:00   23.07.19 22:00:00   25.07.19 04:05:06
AAAAA12334566   23.07.19 22:00:00   25.07.19 04:05:06   22.07.19 22:00:00
AAAAA12334566   25.07.19 04:05:06   25.07.19 04:05:06   01.01.99 00:00:00
AAAAA12334566   25.07.19 04:05:06   01.01.99 00:00:00   24.07.19 04:05:06
BBBBBB12334566  29.06.18 14:59:20   01.02.19 14:25:00   01.02.19 14:25:00
BBBBBB12334566  01.02.19 14:25:00   07.03.19 04:07:48   07.03.19 04:07:48
BBBBBB12334566  07.03.19 04:07:48   05.07.19 04:04:47   09.07.19 04:04:52
BBBBBB12334566  05.07.19 04:04:47   06.07.19 04:04:51   09.07.19 04:04:52
BBBBBB12334566  06.07.19 04:04:51   08.07.19 13:00:45   09.07.19 04:04:52
BBBBBB12334566  08.07.19 13:00:45   08.07.19 13:18:19   12.07.19 04:04:44

我的表中存在HIDTIME_FROMTIME_UNTIL 列。 LAG_TIME_FROM 列由以下 SQL 语句生成,在表中不存在:

Select HID, TIME_FROM, nvl(lead(TIME_FROM) over(partition by HID order by TIME_FROM),timestamp '9999-01-01 00:00:00')  LAG_TIME_FROM, TIME_UNTIL
from my_table
where HID in (

' AAAAA12334566 ',
' BBBBBB12334566 ',
' CCCCCC12334566 ',
' DDDDD12334566 ',
'EEEEEEE12334566 ',
'GGGGG12334566 ');

我要做的是通过上面写的sql语句(LAG_TIME_FROM)更新TIME_UNTIL列。这是我的尝试:

    UPDATE my_table s1
    SET TIME_UNTIL= ( 

    select LAG_TIME_FROM from(
    select HID, TIME_FROM, nvl(lead(TIME_FROM) over(partition by HID order by TIME_FROM),timestamp '9999-01-01 00:00:00')  LAG_TIME_FROM, TIME_UNTIL
    from my_table
    ) s2 
    Where s1.HID in (
    ' AAAAA12334566 ',
    ' BBBBBB12334566 ',
    ' CCCCCC12334566 ',
    ' DDDDD12334566 ',
    'EEEEEEE12334566 ',
    'GGGGG12334566 ')
    and s1. hid = s2. hid
    and s1. TIME_FROM = s2.TIME_FROM
    and s1. TIME_UNTIL = s2. TIME_UNTIL
    );

但是当我运行代码时出现以下错误:

ORA-01407: 无法将 TIME_UNTIL 更新为 NULL。

我不明白为什么会得到 NULLS,因为当我运行 sql 语句时:

Select HID, TIME_FROM, nvl(lead(TIME_FROM) over(partition by HID order by TIME_FROM),timestamp '9999-01-01 00:00:00')  LAG_TIME_FROM, TIME_UNTIL
    from my_table
    where HID in (

    ' AAAAA12334566 ',
    ' BBBBBB12334566 ',
    ' CCCCCC12334566 ',
    ' DDDDD12334566 ',
    'EEEEEEE12334566 ',
    'GGGGG12334566 ');

一切看起来都很好

【问题讨论】:

为什么要这样做?您应该努力避免数据库中的冗余。最好创建一个视图,也许是一个物化视图。 【参考方案1】:

nvl()(或者我喜欢的coalesce())移到子查询之外

UPDATE my_table s1
    SET TIME_UNTIL = coalesce((select LAG_TIME_FROM
                               from (select t.*,
                                            lead(TIME_FROM) over(partition by HID order by TIME_FROM) as LAG_TIME_FROM
                                     from my_table t
                                    ) s2 
                               where s1.hid = s2. hid and
                                     s1.TIME_FROM = s2.TIME_FROM and
                                     s1. TIME_UNTIL = s2.TIME_UNTIL
                              ), timestamp '9999-01-01 00:00:00'
                             )
where s1.HID in (' AAAAA12334566 ',
                 ' BBBBBB12334566 ',
                 ' CCCCCC12334566 ',
                 ' DDDDD12334566 ',
                 'EEEEEEE12334566 ',
                 'GGGGG12334566 '
                );

【讨论】:

【参考方案2】:

只需在更新语句中的外部选择后添加一个条件

     where LAG_TIME_FROM IS NOT 
    NULL

【讨论】:

【参考方案3】:

未格式化,阅读困难,我稍微格式化了一下。

UPDATE my_table s1
  SET TIME_UNTIL = 
    (select LAG_TIME_FROM 
     from (select HID, 
                  TIME_FROM, 
                  nvl(lead(TIME_FROM) over(partition by HID order by TIME_FROM), 
                      timestamp '9999-01-01 00:00:00'
                     ) LAG_TIME_FROM, 
                     TIME_UNTIL
           from my_table
          ) s2 
     Where s1.HID in (' AAAAA12334566 ',    --> are there really leading and
                      ' BBBBBB12334566 ',   --> trailing spaces here?
                      ' CCCCCC12334566 ',
                      ' DDDDD12334566 ',
                      'EEEEEEE12334566 ',
                      'GGGGG12334566 '
                     )
       and s1. hid = s2. hid                --> there shouldn't be any space between alias and
       and s1. TIME_FROM = s2.TIME_FROM     --> column names
       and s1. TIME_UNTIL = s2. TIME_UNTIL
    );

IN 元素中真的有前导和尾随空格吗?

除此之外,您似乎只想更新一些 s1 行,但您的查询正在更新 所有 行 - 其中一些更新为 NULL,因此 Oracle 抱怨列为最有可能声明为NOT NULL

这意味着您必须限制要更新的行。也许将IN 子句移出子查询会有所帮助,例如

UPDATE my_table s1
  SET TIME_UNTIL = 
    (select LAG_TIME_FROM 
     from (select HID, 
                  TIME_FROM, 
                  nvl(lead(TIME_FROM) over(partition by HID order by TIME_FROM), 
                      timestamp '9999-01-01 00:00:00'
                     ) LAG_TIME_FROM, 
                     TIME_UNTIL
           from my_table
          ) s2 
     where 1 = 1                            --> placeholder for now missing IN clause
       and s1.hid = s2. hid                
       and s1.TIME_FROM = s2.TIME_FROM     
       and s1.TIME_UNTIL = s2. TIME_UNTIL
    )
Where s1.HID in (' AAAAA12334566 ',    --> are there really leading and
                 ' BBBBBB12334566 ',   --> trailing spaces here?
                 ' CCCCCC12334566 ',
                 ' DDDDD12334566 ',
                 'EEEEEEE12334566 ',
                 'GGGGG12334566 '
                );

看看有没有帮助;如果没有,你将不得不修复它。如何?你应该知道,你有数据。 EXISTS 子句通常在这种情况下会有所帮助。

【讨论】:

别名和列名之间不应有任何空格 - @Littlefoot 您在 Oracle 文档或标准中有一些证据吗?虽然可能不是审美,但这些空间似乎完全没问题:select DUAL . DUMMY from dual。如果我用你的逻辑解释Column Expressions,同样的论点将导致只允许使用1+1,而不是1 + 1 ... 嗯,从我的角度来看,e. ename1 + 1、@Marmite 完全不同,但是是的 - 今天我学到了一些新的和令人兴奋的东西。没错,它确实有效。当然,我没有任何证据,因为没有。我只是在想空间是错误。甚至从未见过有人分开写它。非常感谢您的提示,我会修复我的消息。

以上是关于使用子查询 (Oracle) 更新表的主要内容,如果未能解决你的问题,请参考以下文章

连接两个表子查询

mysql子查询

sqlserver根据子查询更新语句

MySQL------ 子查询

MySQL------ 子查询

MySQL随记 - 子查询