基于依赖表更新表

时间:2011-11-29 14:52:33

标签: sql oracle foreign-keys

设置


我有两个表,USERSPETS

每个用户都有一个ID,一个NAME和一个标记HAS_PETS,如果用户拥有至少一只宠物,则为1,否则为0。

每个pet都有一个ID,一个NAME和一个OWNER_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);

问题


有一次,许多宠物被添加到PETS,但OWNER表的HAS_PETS标记未更新。在上面的示例数据中,Carol拥有Xerxes,但她的旗帜为0。

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

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

但它会出错,cannot modify a column which maps to a non key-preserved table。 Oracle建议我Modify 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

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

问题

  • 第一个错误是什么意思? HAS_PETS属于USERS,它有一个主键。我在这里看不到任何非密钥保留的表。
  • 如何修改我的声明,使其按照我期望的方式执行?

2 个答案:

答案 0 :(得分:3)

你可以尝试

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

答案 1 :(得分:2)

根据Oracle documentation,密钥保留表是表中的密钥保留在连接中的表。

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

由于PETS表是密钥保留的,您可以使用更新连接语法(例如)使用USER的名称更新PETS表,但不能使用来自PETS的信息更新USERS表。