使用子查询 (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
我的表中存在HID
、TIME_FROM
和TIME_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. ename
与1 + 1
、@Marmite 完全不同,但是是的 - 今天我学到了一些新的和令人兴奋的东西。没错,它确实有效。当然,我没有任何证据,因为没有。我只是在想空间是错误。甚至从未见过有人分开写它。非常感谢您的提示,我会修复我的消息。以上是关于使用子查询 (Oracle) 更新表的主要内容,如果未能解决你的问题,请参考以下文章