我有一个存储过程接受表类型并将值插入表中。我通过在参数中传递1000本书来调用此存储过程。但我想处理异常,即使参数中的一行或两行失败插入,也应该插入其他行。我该怎么做?
CREATE PROCEDURE InsertBooks
@newBooks BooksTable READONLY
AS
INSERT INTO book
SELECT @newBooks
提前致谢。
答案 0 :(得分:1)
您可以通过设置insert语句来防止各个行导致错误。单个行可能无法从table参数正确插入实际表中有两个原因:
架构不匹配。您可以通过确保表参数的模式与目标表的模式完全匹配来防止这种情况。
违反约束条件。通过对输入运行过滤器查询来防止这种情况,因此在插入之前会从数据中删除坏行。最可能的版本是无效密钥,但无论约束类型如何,都适用相同的规则。
例如,让我们说你的book表有一个作者的外键,authorID。您可以像这样过滤输入:
SELECT nb.*
FROM @newBooks nb
INNER JOIN authors a
ON nb.authorID = a.authorID
然后,您可以将此查询的结果插入到书中,而不必担心新数据中可能存在无效作者。
另外一个注意事项:如果您尝试插入特定的主键值,则必须在插入任何数据之前过滤掉重复项以及SET IDENTITY_INSERT book ON
。在你完成之后不要忘记关闭IDENTITY_INSERT。
答案 1 :(得分:0)
如果您只是想要重复(根据UNIQUE
索引/约束)忽略而不单独跟踪,那么可以通过启用唯一索引或唯一约束的IGNORE_DUP_KEY
选项来轻松完成,如以下示例所示:
IF (OBJECT_ID(N'tempdb..#tmp') IS NOT NULL)
BEGIN
DROP TABLE #tmp;
END;
CREATE TABLE #tmp
(
TmpID INT IDENTITY(1, 1) NOT NULL PRIMARY KEY CLUSTERED,
Code VARCHAR(10) NOT NULL UNIQUE WITH (IGNORE_DUP_KEY = ON),
OtherValue INT NOT NULL
);
INSERT INTO #tmp (Code, OtherValue)
SELECT tab.ColA, tab.ColB
FROM (
VALUES ('A', 1), ('B', 1), ('C', 1), ('B', 2),
('B', 3), ('C', 2), ('D', 1), ('B', 4)
) tab(ColA, ColB)
--ORDER BY tab.ColB DESC;
SELECT *
FROM #tmp;
返回:
-- no ORDER BY (i.e. ORDER BY is commented out):
TmpID Code OtherValue
1 A 1
2 B 1
6 C 2
7 D 1
-- using the ORDER BY:
TmpID Code OtherValue
4 C 2
6 D 1
7 B 1
8 A 1
请注意:
如上面的示例输出所示,当存在重复项时,您无法完全控制首先插入哪个项目以及哪些项目被视为重复项目。
启用此选项会导致性能下降。有关其他详细信息,请参阅以下博文:Maintaining Unique Indexes with IGNORE_DUP_KEY