INSERT INTO PERSONS_V VALUES (123456, 'Smith', NULL, NULL, NULL, NULL), (234567, 'Jones', 'Wmart', 20000, NULL, NULL), (345678, 'Miller', NULL, NULL, 'Harvard', 'Math'), (456789, 'McNuts', 'SelfEmp', 60000, 'UCLA', 'CS')$ SELECT * FROM PERSONS_V ORDER BY SSN$ SSN NAME COMPANY SALARY UNIVERSITY MAJOR ------ ------ -------- -------- ----------- ------ 123456 Smith - - - - 234567 Jones Wmart 20000.00 - - 345678 Miller - - Harvard Math 456789 McNuts SelfEmp 60000.00 UCLA CS 现在 Smith 先生结婚了,采用他妻子的姓“Johnson”,并且他以 15000 的工资被 Mickburgs 聘用,而 Miller 女士从 Harvard 毕业并被 IBM 聘用。 UPDATE PERSONS_V SET (name, company, salary) = ('Johnson', 'Mickburgs', 15000) WHERE SSN = 123456$ UPDATE PERSONS_V SET (company, salary, university) = ('IBM', 70000, NULL) WHERE SSN = 345678$ SELECT * FROM PERSONS_V WHERE SSN IN (123456, 345678) ORDER BY SSN$ SSN NAME COMPANY SALARY UNIVERSITY MAJOR ------ ------- -------- -------- ----------- ------ 123456 Johnson Mickburgs 15000 - - 345678 Miller IBM 70000 - - Jones 先生长期出国: DELETE FROM PERSONS_V WHERE NAME = 'Jones'$ 最后说明一点,在插入时我们可以省略值为 NULL 的列: INSERT INTO PERSONS_V(ssn, name) VALUES (567890, 'vanderpoor')$ 既然这么说了,那么谈论 DEFAULTS 就有意义了。我们将在下一个(也就是最后一个)示例中谈谈这一点及其它。 异常表处理 将数据插入表时,就会使用数据类型、BEFORE 触发器、检查约束和 RI 约束来限制用某种方式或其它方式插入的数据。SET INTEGRITY、LOAD 和 IMPORT 都允许用户通过将被拒绝的行存储到异常表中来处理有问题的数据。但是,INSERT 和 UPDATE 自身并没有办法可处理有问题的数据。应用程序负责尝试诸如插入之类的操作,如果失败了,就采取必要的步骤。不便之处在于两个方面: - 首先,处理不是封装的。
- 其次,单行插入很浪费,即使通过存储过程完成时也是如此。
CREATE TABLE ADDRESSES(name varchar(10), number INT, street varchar(20), country VARCHAR(10) WITH DEFAULT 'CANADA')$ CREATE TABLE BAD_ADDRESSES AS (SELECT CAST(NULL AS VARCHAR(30)) AS Reason, A.* FROM ADDRESSES A) DEFINITION ONLY$ CREATE VIEW ADDRESSES_V AS SELECT * FROM ADDRESSES$ CREATE TRIGGER INSERT_ADDRESSES_V INSTEAD OF INSERT ON ADDRESSES_V REFERENCING NEW AS n FOR EACH ROW MODE DB2SQL BEGIN ATOMIC DECLARE reason VARCHAR(30); SET reason = CASE WHEN n.number IS NULL OR n.number <= 0 THEN 'Number' WHEN n.name IS NULL OR LENGTH(n.name) = 0 THEN 'Name' WHEN n.street IS NULL OR LENGTH(n.street) = 0 THEN 'Street' WHEN country IS NULL OR country NOT IN ('CANADA', 'USA', 'GERMANY', 'FRANCE') THEN 'Country' ELSE NULL END; IF reason IS NOT NULL THEN INSERT INTO BAD_ADDRESSES VALUES(reason, n.name, n.number, n.street, n.country); ELSE INSERT INTO ADDRESSES VALUES(n.name, n.number, n.street, n.country); END IF; END$ 上面的触发器将把好的数据和有问题的数据分隔开来,并存储相应的地址。但是这个示例还说明了其它更多的东西。 请注意,当前的 DB2 V8 文档规定 INSTEAD OF 触发器应当将列的所有 DEFAULT 值看成 NULL,这一点很重要。这个行为是由于 DB2 V8 Beta 测试版的客户反馈而进行的更改,因此从 INSTEAD OF 触发器规范中删除了 DEFAULTS NULL 子句。 当定义视图时,对于可更新列从底层表中继承其列的缺省值。如果列(在没有 INSTEAD OF 触发器的帮助下)是不可更新的,那么认为 DEFAULT 为 NULL。在本例中,如果没有指定国家或地区(country),或者如果使用了关键字 DEFAULT,那么 INSTEAD OF 触发器将获取“CANADA”。对于其它所有列该触发器将获取 NULL。 INSERT INTO ADDRESSES_V VALUES ('Jones', 510, 'Yonge St.', DEFAULT), ('Smith', -1, 'Nowhere', 'USA'), (NULL, 38, 'Am Feldweg', 'GERMANY'), ('Poubelle', 23, 'Rue de Jardin', 'FRANCE')$ SELECT * FROM ADDRESSES ORDER BY name$ NAME NUMBER STREET COUNTRY ---------- ------ -------------- ------- Jones 510 Yonge St. CANADA Poubelle 23 Rue de Jardin FRANCE SELECT * FROM BAD_ADDRESSES ORDER BY name$ REASON NAME NUMBER STREET COUNTRY ------ ------- ------ ----------- ------- Number Smith -1 Nowhere USA Name - 38 Am Feldweg GERMANY 可以轻松地调整该触发器以忽略有问题的行而不是将它们存储起来。 更多想法…… INSTEAD OF 触发器的其它应用可能有: 





