捕获 Teradata 中的插入错误
Capture insert error in Teradata
我有一个存储过程使用以下语句将记录插入我们的 Teradata 数据仓库中的 table:
INSERT INTO UAT_AUDIT_VIEWS.AUDIT_BATCH(
BATCH_KEY
,AUDIT_STATUS_KEY
,BATCH_START_DATETIME
,BATCH_END_DATETIME
,BATCH_OWNER
,BATCH_EXECUTION_START_DATETIME
,BATCH_EXECUTION_END_DATETIME
)
VALUES(
(SELECT COALESCE(MAX(BATCH_KEY),0)+1 FROM UAT_AUDIT_VIEWS.AUDIT_BATCH)
,5 --PENDING
,'1900-01-01 00:00:00'
,'2999-12-31 00:00:00'
,:P_BATCH_OWNER
,CURRENT_TIMESTAMP
,'2999-12-31 00:00:00'
);
请注意,我对主键有唯一性约束 BATCH_KEY。在某些情况下,我的插入语句会失败,因为主键已经存在于 table 中。当它发生时,我希望我的存储过程循环并重试插入直到成功。
我使用以下方法尝试了多种解决方案但未成功:
DECLARE CONTINUE HANDLER FOR SQLEXCEPTION
避免插入失败时存储过程失败
WHILE DO
循环重试插入
您能否描述一下您将如何应对这种情况?
这是我为测试它而构建的测试存储过程的简化版本(没有用):
REPLACE PROCEDURE DEV_AUDIT_NEW.ARO_TEST_INSERT()
BEGIN
DECLARE V_BATCH_KEY_CREATED VARCHAR(100);
DECLARE V_COUNTER SMALLINT DEFAULT 1;
DECLARE CONTINUE HANDLER FOR SQLEXCEPTION
SET V_BATCH_KEY_CREATED = NULL;
WHILE V_BATCH_KEY_CREATED IS NULL
DO
INSERT INTO DEV_AUDIT_NEW.AUDIT_BATCH_TEST_LOG(LOG_DESC) VALUES(V_BATCH_KEY_CREATED);
INSERT INTO DEV_AUDIT_NEW.AUDIT_BATCH_TEST(BATCH_KEY,BATCH_OWNER) VALUES(V_COUNTER,'B');
SELECT BATCH_KEY
INTO :V_BATCH_KEY_CREATED
FROM DEV_AUDIT_NEW.AUDIT_BATCH_TEST
WHERE BATCH_KEY=V_COUNTER AND BATCH_OWNER='B';
SET V_COUNTER=V_COUNTER+1;
INSERT INTO DEV_AUDIT_NEW.AUDIT_BATCH_TEST_LOG(LOG_DESC) VALUES(V_BATCH_KEY_CREATED);
END WHILE;
END;
这条评论太长了。
您当前的方法必须执行完整 Table 扫描以获得 MAX(默认为 table 级别的读锁),但插入默认为行哈希级别的写锁。当您请求写入 table 级别时,它应该可以防止死锁。
当您定义一种序列时 table 每个访问都是 UPI 访问,例如
CREATE SET TABLE Sequences
(
SequenceName VARCHAR(128) CHARACTER SET Unicode NOT CaseSpecific NOT NULL,
nextVal BIGINT NOT NULL DEFAULT 1
)
UNIQUE PRIMARY INDEX ( SequenceName )
;
REPLACE PROCEDURE NextVal (IN SequenceName VARCHAR(128) CHARACTER SET Unicode, OUT NextVal BIGINT)
BEGIN
BEGIN REQUEST
LOCK ROW WRITE
SELECT nextVal INTO :nextVal FROM Sequences
WHERE SequenceName = :SequenceName;
UPDATE Sequences SET nextVal = nextVal + 1
WHERE SequenceName = :SequenceName;
END REQUEST;
END;
初始化一个新序列:
INSERT INTO sequences ('mytable', 1);
获取下一个值:
CALL nextVal('mytable', nextval);`
编辑:
您可以使用 BTEQ 轻松测试它,并行记录多个会话,例如到 运行 10 个会话中的 1000 个呼叫:
.set session 10;
.logon ...;
select * from sequences where SequenceName = 'mytable';
.repeat 1000
CALL nextVal('mytable', nextval);
select * from sequences where SequenceName = 'mytable';
观察按顺序返回的值,没有死锁:-)
我有一个存储过程使用以下语句将记录插入我们的 Teradata 数据仓库中的 table:
INSERT INTO UAT_AUDIT_VIEWS.AUDIT_BATCH(
BATCH_KEY
,AUDIT_STATUS_KEY
,BATCH_START_DATETIME
,BATCH_END_DATETIME
,BATCH_OWNER
,BATCH_EXECUTION_START_DATETIME
,BATCH_EXECUTION_END_DATETIME
)
VALUES(
(SELECT COALESCE(MAX(BATCH_KEY),0)+1 FROM UAT_AUDIT_VIEWS.AUDIT_BATCH)
,5 --PENDING
,'1900-01-01 00:00:00'
,'2999-12-31 00:00:00'
,:P_BATCH_OWNER
,CURRENT_TIMESTAMP
,'2999-12-31 00:00:00'
);
请注意,我对主键有唯一性约束 BATCH_KEY。在某些情况下,我的插入语句会失败,因为主键已经存在于 table 中。当它发生时,我希望我的存储过程循环并重试插入直到成功。
我使用以下方法尝试了多种解决方案但未成功:
DECLARE CONTINUE HANDLER FOR SQLEXCEPTION
避免插入失败时存储过程失败WHILE DO
循环重试插入
您能否描述一下您将如何应对这种情况? 这是我为测试它而构建的测试存储过程的简化版本(没有用):
REPLACE PROCEDURE DEV_AUDIT_NEW.ARO_TEST_INSERT()
BEGIN
DECLARE V_BATCH_KEY_CREATED VARCHAR(100);
DECLARE V_COUNTER SMALLINT DEFAULT 1;
DECLARE CONTINUE HANDLER FOR SQLEXCEPTION
SET V_BATCH_KEY_CREATED = NULL;
WHILE V_BATCH_KEY_CREATED IS NULL
DO
INSERT INTO DEV_AUDIT_NEW.AUDIT_BATCH_TEST_LOG(LOG_DESC) VALUES(V_BATCH_KEY_CREATED);
INSERT INTO DEV_AUDIT_NEW.AUDIT_BATCH_TEST(BATCH_KEY,BATCH_OWNER) VALUES(V_COUNTER,'B');
SELECT BATCH_KEY
INTO :V_BATCH_KEY_CREATED
FROM DEV_AUDIT_NEW.AUDIT_BATCH_TEST
WHERE BATCH_KEY=V_COUNTER AND BATCH_OWNER='B';
SET V_COUNTER=V_COUNTER+1;
INSERT INTO DEV_AUDIT_NEW.AUDIT_BATCH_TEST_LOG(LOG_DESC) VALUES(V_BATCH_KEY_CREATED);
END WHILE;
END;
这条评论太长了。
您当前的方法必须执行完整 Table 扫描以获得 MAX(默认为 table 级别的读锁),但插入默认为行哈希级别的写锁。当您请求写入 table 级别时,它应该可以防止死锁。
当您定义一种序列时 table 每个访问都是 UPI 访问,例如
CREATE SET TABLE Sequences
(
SequenceName VARCHAR(128) CHARACTER SET Unicode NOT CaseSpecific NOT NULL,
nextVal BIGINT NOT NULL DEFAULT 1
)
UNIQUE PRIMARY INDEX ( SequenceName )
;
REPLACE PROCEDURE NextVal (IN SequenceName VARCHAR(128) CHARACTER SET Unicode, OUT NextVal BIGINT)
BEGIN
BEGIN REQUEST
LOCK ROW WRITE
SELECT nextVal INTO :nextVal FROM Sequences
WHERE SequenceName = :SequenceName;
UPDATE Sequences SET nextVal = nextVal + 1
WHERE SequenceName = :SequenceName;
END REQUEST;
END;
初始化一个新序列:
INSERT INTO sequences ('mytable', 1);
获取下一个值:
CALL nextVal('mytable', nextval);`
编辑:
您可以使用 BTEQ 轻松测试它,并行记录多个会话,例如到 运行 10 个会话中的 1000 个呼叫:
.set session 10;
.logon ...;
select * from sequences where SequenceName = 'mytable';
.repeat 1000
CALL nextVal('mytable', nextval);
select * from sequences where SequenceName = 'mytable';
观察按顺序返回的值,没有死锁:-)