0

我正在尝试使用此更改表的主要,

ACCEPT p_oldserial PROMPT 'Enter Old Serial: ';
ACCEPT p_newserial PROMPT 'Enter New Serial: ';
INSERT INTO car
(SELECT serial, cname, make, model, year, color, trim, enginetype, purchinv, purchdate, purchfrom, purchcost, freight, totalcost, listprice
   FROM customer
  WHERE serial='&p_oldserial');
UPDATE saleinv
   SET serial='&p_newserial'
 WHERE serial='&p_oldserial';
UPDATE serivceinv, saleinv;
DELETE FROM customer
 WHERE serial='&p_oldserial';
COMMIT;

但我得到了 ORA-02291。我的脚本有错误吗?

4

2 回答 2

2

你的问题是“我的脚本有什么错误吗?”。

答案是“是的,非常肯定”,但也许不是你想的那样。这不是语法错误,很容易修复。这是一个很难处理的逻辑和理解问题。

主键具有三个基本属性:

  1. 它是独一无二的。
  2. 它不为空。
  3. 它是不变的。

你试图违反规则#3。现在,在所有其他条件相同的情况下,Oracle(以及我曾经使用过的所有其他关系数据库)将允许您随意违反规则 #3。但是,在这种情况下,有另一个表具有 FOREIGN KEY 约束,它引用您尝试更改的主键。在 UPDATE 语句执行后,Oracle 检查所有可能受到影响的外键约束,并发现其中一个已被违反,因为 'child' 表上的键值不再存在于 'parent' 表中(SALEINV在这种情况下的表)。

在这一点上,一个常见的反应是说,“愚蠢的数据库!关系数据库明显坏了! 聪明多了!!外键约束不好,必须消除!!!”。所以开发者愤怒地从悬崖上走下来,疯狂地删除外键,想知道为什么会有这么多风,无论如何。我的意思是,这是怎么回事……< SPLAT!>?

事实上,外键约束只是让你免于做一些非常非常糟糕的事情 - 非常糟糕,事实上,它看起来像是在做一些非常非常好的事情,但不,老实说,从我这里拿走它,更改主键是真的很糟糕。(不要问我是怎么知道的...... :-)。那个主键是让你知道有问题的行总是和永远相同的东西,如果你改变它,你就是在说“这个以前是 ABC 现在是 XYZ 的东西,而且它所指的任何地方现在都必须指的是 XYZ”。把它想象成你数据库中的“身体抢夺者入侵”——一旦你开始这样做,你就不再相信任何东西都会保持原样,你不能安全地将任何行与任何其他行关联起来,因为键可能会改变,你可以'

最终分析 - 找出其他方法来做你想做的事。除此之外,您是否真的建议您更改车辆的 VIN?这是另一件坏事,我怀疑有很多执法机构会很乐意解释原因...... :-)

分享和享受。

于 2012-07-11T11:38:27.873 回答
1

第一个问题是哪个语句失败了。一次执行一个语句。我希望它是 DELETE 语句。

DELETE FROM customer
WHERE serial='&p_oldserial';

如果是这样,您还没有移动使用外键引用该行的所有记录。第二次更新应该读吗?

UPDATE serviceinv
SET    serial='&p_newserial'
WHERE  serial='&p_oldserial';

还有其他需要类似更新的表吗?

正如其他人所指出的,主键通常被认为是不可变的。因此,这应该是一次性的改变。如果这可能是一个频繁的更改,那么您可能需要一个代理键。这会将更新减少到:

UPDATE car
SET    serial='&p_newserial'
WHERE  serial='&p_oldserial';

如果这可能是频繁更改并且您无法添加代理键,请查看 CASCADE 选项。

于 2012-07-11T00:24:48.120 回答