基于另一个表更新行

Update rows based on another table

提问人:Kevin 提问时间:8/29/2012 最后编辑:CommunityKevin 更新时间:8/29/2012 访问量:4345

问:

我有一个表格,用于跟踪我库存中链轮的物理质量。

create table sprockets(
    id NUMBER,
    mass NUMBER
);

INSERT into sprockets VALUES (1, 4);
INSERT into sprockets VALUES (2, 8);
INSERT into sprockets VALUES (3, 15);
INSERT into sprockets VALUES (4, 16);
INSERT into sprockets VALUES (5, 23);
INSERT into sprockets VALUES (6, 42);

我雇用链轮机械师对我的链轮进行日常维护。如果他们的修改使链轮的质量发生变化,他们会在维护报告中记录下来。

create table maintenance_events(
    sprocket_id NUMBER,
    new_mass NUMBER
);

--chipped a widget off of sprocket #1; mass reduced to 3 kg
INSERT into maintenance_events VALUES (1, 3);       
--new lead bearings makes sprocket #2 weigh 413 kg
INSERT into maintenance_events VALUES (2, 413);     

我想用每个链轮的当前质量更新表格。我想接受并覆盖 中的旧值。我参考了这个问题的前两个答案,但都给出了错误。sprocketsnew_massmaintenance_eventsmasssprockets

UPDATE sprockets
set mass = maintenance_events.new_mass
from sprockets, maintenance_events
where sprockets.id = maintenance_events.sprocket_id

Error at Command Line:2 Column:38
Error report:
SQL Error: ORA-00933: SQL command not properly ended

UPDATE sprockets
set sprockets.mass = maintenance_events.new_mass
from sprockets
INNER JOIN maintenance_events
on sprockets.id = maintenance_events.sprocket_id

Error at Command Line:2 Column:48
Error report:
SQL Error: ORA-00933: SQL command not properly ended

我做错了什么?

Oracle11g SQL 更新

评论

0赞 Joe 8/29/2012
除非您只保留每个链轮的最新维护事件,否则您可能还希望在该表中存储日期,以便您可以确定您使用的是该链轮的最新值
1赞 Esoteric Screen Name 8/29/2012
可能的重复项:stackoverflow.com/questions/2446764/...
0赞 swasheck 8/29/2012
是否所有语句都以分号结尾?我找到了这个链接
0赞 Kevin 8/29/2012
@Joe,这在我的 2.0 版本列表中。目前,我的维护数据集保证具有唯一的链轮 ID。
0赞 rfusca 8/29/2012
链接的 Q 与 SQL Server 有关。Oracle 不支持“UPDATE...从......”

答:

2赞 swasheck 8/29/2012 #1

这又如何呢?

UPDATE sprockets
SET sprockets.mass = (select new_mass 
                           from maintenance_events 
                      where sprockets.id = maintenance_events.sprocket_id)
WHERE EXISTS (select new_mass 
                           from maintenance_events 
                      where sprockets.id = maintenance_events.sprocket_id);

评论

0赞 Kevin 8/29/2012
它说,命令行错误:1 列:16 SQL 错误:ORA-00971:缺少 SET 关键字
0赞 swasheck 8/29/2012
哎呀。现在就试试。我一定对我的 WHERE 和 SET 位置感到困惑
0赞 Kevin 8/29/2012
现在我收到前两次尝试中遇到的错误,“Sql命令未正确结束”
2赞 rfusca 8/29/2012
如果您的sprocket_id有多个记录,那么这将被打破。
1赞 heretolearn 8/29/2012 #2

试试这个:

UPDATE sprockets
set mass = (select maintenance_events.new_mass
from maintenance_events
where sprockets.id = maintenance_events.sprocket_id) where exists 
(select maintenance_events.sprocket_id from maintenance_events 
 where sprockets.id = maintenance_events.sprocket_id);

你可以在这里查看:http://sqlfiddle.com/#!5/f4262/11/0

评论

0赞 Kevin 8/29/2012
这在一定程度上有效,因为它将链轮 1 的质量设置为预期的 5。但是,我的所有其他质量都设置为空!还好我做了一个备份:-)
0赞 swasheck 8/29/2012
是,此查询不包含筛选器
3赞 Ben 8/29/2012 #3

这就是 merge 的用途,一个 upsert:

merge into sprockets s
using ( select * from maintenance_events ) m
on (s.id = m.sprocket_id)
when matched then
 update 
    set s.mass = m.new_mass
        ;

这比使用等进行多次表扫描要高效得多。where not exists

这里有一个 SQL 小提琴来证明它有效。

评论

0赞 rfusca 8/29/2012
但是,在合并查询中,您需要做的是具有某种时间戳字段等,并且仅获取每个sprocket_id的最新记录。
0赞 Ben 8/29/2012
@rfusca,您不需要这样做,仅当 中有多个 in ,但此表中没有时间戳时。不过,您可以轻松地添加或类似于 and 子句来绕过它。maintenance_eventsrank() over ( partition by sprocket_id order by new_mass ) as rnkselectrnk = 1on
0赞 rfusca 8/29/2012
好吧,我假设他的现实世界maintenance_event每个链轮将有不止一条记录,否则只需更新链轮表即可。
0赞 rfusca 8/29/2012
在问题的范围内使用等级是武断的,但在现实世界中却是愚蠢的。没有理由认为链轮的质量只会增加或减少。
0赞 Ben 8/29/2012
@rfusca,这就是我的观点......由于表中没有时间戳,因此没有时间戳,您的问题将完全不确定。,将与给出的其他查询完全相同,如果有多个查询,则失败。但是,它更有效率。mergesprocket_id