基于依赖表更新表

Updating A Table Based On A Dependent Table

提问人:Kevin 提问时间:11/29/2011 最后编辑:Mahmoud GamalKevin 更新时间:11/29/2011 访问量:1718

问:

设置


我有两张表,还有.USERSPETS

每个用户都有一个 、 和 一个标志 ,如果用户拥有至少一只宠物,则为 1,否则为 0。IDNAMEHAS_PETS

每个都有 、 和 。下面是创建脚本:petIDNAMEOWNER_ID

create table USERS(
ID NUMBER(*,0),
NAME VARCHAR2(50 BYTE),
HAS_PETS NUMBER(1,0),
CONSTRAINT "XPKUSERS" PRIMARY KEY ("ID")
);

create table PETS(
ID NUMBER(*,0),
NAME VARCHAR2(50 BYTE),
OWNER_ID NUMBER(*,0),
CONSTRAINT "XPKPETS" PRIMARY KEY ("ID")
);

insert into USERS values(0, 'Alice', 0);
insert into USERS values(1, 'Bob', 1);
insert into USERS values(2, 'Carol', 0);

insert into PETS values(0, 'Fido', 1);
insert into PETS values(1, 'Spot', 1);
insert into PETS values(2, 'Xerxes', 2);

问题


有一次,许多宠物被添加到,但表的标志没有更新。在上面的示例数据中,Carol 拥有 Xerxes,但她的标志是 0。PETSOWNERHAS_PETS

我想写一个声明,如果主人有宠物,该声明将设置为 true。根据上述数据,它应该将 Carol 的标志设置为 1。 我试过了这个:HAS_PETSHAS_PETS

update (
select * 
from USERS a join PETS b 
on a.HAS_PETS = 0 and a.ID = b.OWNER_ID
)
set HAS_PETS = 1 

但它给出了一个错误,.Oracle 建议我 ,但除非我执行此联接,否则我无法确定哪些行需要更新。cannot modify a column which maps to a non key-preserved tableModify the underlying base tables directly

谷歌搜索促使我尝试这种替代语法:

update a
set a.HAS_PETS = 1
from USERS a join PETS b 
on a.HAS_PETS = 0 and a.ID = b.OWNER_ID

但它给出了一个错误,维基百科说“某些数据库允许非标准地使用 FROM 子句”,这让我相信 Oracle 不支持这一点。SQL command not properly ended

问题

  • 第一个错误的含义是什么?HAS_PETS属于 USERS,它有一个主键。我在这里没有看到任何非键保留的表。
  • 如何修改我的语句,使其按照我期望的方式执行?
SQL Oracle 外键

评论

0赞 Allan 11/30/2011
我意识到这可能不是一个现实世界的问题,但值得指出的是,这通常被认为是一个糟糕的设计。添加指示子记录存在的标志是一种非规范化:如果只是在需要该信息时检查子记录,则问题不存在。
0赞 Kevin 11/30/2011
@Allan,这些表确实存在,尽管我更改了名称以匿名化它们。该标志存在的原因是 .Net 前端使用 NHibernate 延迟加载 User 对象。如果我们访问用户的 Pet 集合,Hibernate 必须执行额外的查询。访问该标志不需要额外的工作。(或者至少这似乎是原始开发人员的推理)

答:

3赞 Marco 11/29/2011 #1

你可以试试

UPDATE a SET HAS_PETS = 1
WHERE ID IN 
    (SELECT DISTINCT OWNER_ID FROM b) p

使用您的附加条件可能会更快(感谢@jadarnel27注意到这一点)

UPDATE a SET HAS_PETS = 1
WHERE HAS_PETS = 0 
  AND ID IN 
    (SELECT DISTINCT OWNER_ID FROM b) p

评论

0赞 Josh Darnell 11/29/2011
嗯。。。看起来您错过了其中一个条件 (a.HAS_PETS = 0)。而且,您没有回答有关错误消息 =/ 的 OPs 问题。而且,你打错了WHEREUPDATE
0赞 Marco 11/29/2011
@jadarnel27:我不是甲骨文大师,所以我无法回答OP的第一个问题。第二个查询已纠正,我认为您提到的条件没有用......只是让查询更快,但这不是必需的。感谢您的建议!:)
0赞 Josh Darnell 11/29/2011
+1,我没有想到附加条件与其说是要求,不如说是优化 - 好点 =)
2赞 Mike Meyers 11/29/2011 #2

根据 Oracle 文档,保留键的表是表的键保留在联接中的表。

在此示例中,PETS 表是密钥保留,但 USERS 表不是。这是因为每个 USER 可能具有多个 PET,因此 USERS 表的主键可能会在结果集中多次出现。

由于 PETS 表保留键,因此可以使用更新联接语法(例如)使用 USER 的名称更新 PETS 表,但不能使用 PETS 中的信息更新 USERS 表。

评论

0赞 Kevin 11/30/2011
感谢您提供信息丰富的链接和解释!我真的应该停止问多部分问题,因为不同的人回答不同的部分,很难决定给谁打绿色复选标记。Marco 因为解决了我的实际问题而得到了支票,但请接受这个 +1 来解释我的理论问题。
0赞 Mike Meyers 11/30/2011
我喜欢使用这种形式的更新,但有太多限制,很难做到正确。多亏了你的问题,我现在也很好地理解了什么是密钥保留表。