问题(1):
是否可以创建一个插入一组代码的try-catch以及何时抛出错误
(例如:Violation of PRIMARY KEY constraint 'PK_CouponNumber'. Cannot insert duplicate key in object 'dbo.CouponNumber'.
),
它会跳过该值并继续插入其余代码吗?
我当前的代码是这样的SP:
DECLARE @Success BIT
SELECT @RetryCount = 1, @Success = 0
WHILE @Success = 0
BEGIN
BEGIN TRY
BEGIN TRANSACTION
CREATE TABLE dbo.RandomGenerator(
RowNumber INT PRIMARY KEY CLUSTERED,
NextID INT )
;WITH x AS (
SELECT TOP (1000000) rn = ROW_NUMBER() OVER (ORDER BY s1.[object_id])
FROM sys.all_objects AS s1
CROSS JOIN sys.all_objects AS s2
ORDER BY s1.[object_id]
)
INSERT dbo.RandomGenerator(RowNumber, NextID)
SELECT rn, ROW_NUMBER() OVER (ORDER BY NEWID()) + 1000000 FROM x;
INSERT INTO dbo.RandomNumbers( EventID, RandomID, UserID)
SELECT TOP (@Number) @EventID, NextID, @UserID FROM RandomGenerator
COMMIT TRANSACTION
SELECT 'Success!'
SELECT @Success = 1 -- To exit the loop
END TRY
BEGIN CATCH
ROLLBACK TRANSACTION
SELECT ERROR_NUMBER() AS [Error Number],
ERROR_MESSAGE() AS [ErrorMessage];
IF ERROR_NUMBER() = 2627
BEGIN
--Do Something...
END
END CATCH
END
它的作用就是生成并试着尝试直到成功。
我打算尝试插入所有数字而不重复,然后重复这个过程,直到插入数字的数量等于@Number。
在创建此问题时,我发现了一个相关问题,他们使用IGNORE_KEY_DUP。我想尝试一下,但我不能,因为我不能改变桌子......
问题(2):
有没有办法在不改变表的情况下使用IGNORE_KEY_UP?
预先谢谢!
修改
忘记提到我在插入过程中已尝试过NOT EXIST和NOT IN,但如果表中存在100,000个randomID,则特别慢。所以我把它作为我的选项删除了,我想尝试尝试直到成功插入比比较现有的1M randomID中的每个100,000新的randomID要快得多。
修改
显然我的老板只是允许在此期间更换桌子。所以这就是我所取得的成就
Duplicate key was ignored.
@newCouponCount727012 @generatedCount:227012 @notGeneratedCount:22988
Duplicate key was ignored.
@newCouponCount747842 @generatedCount:247842 @notGeneratedCount:2158
Duplicate key was ignored.
@newCouponCount749846 @generatedCount:249846 @notGeneratedCount:154
Duplicate key was ignored.
@newCouponCount749991 @generatedCount:249991 @notGeneratedCount:9
@newCouponCount750000 @generatedCount:250000 @notGeneratedCount:0
。与使用NOT EXISTS
时的30分钟+相比,这运行时间为14秒。这就是我的意思,尝试尝试直到成功。我知道这与我的问题的标题相矛盾,所以我仍然乐意接受答案/新方法,以防IGNORE_DUP_KEY最终产生更多错误。
答案 0 :(得分:2)
至于您的问题(1),您可以将重复的结果排除在WHERE子句中。由于我们没有dbo.CouponNumber
的查询,我只能举个例子:
INSERT INTO dbo.MyTable (MyPKColumn1, MyPKColumn2)
SELECT RowNumber, NextID
FROM dbo.RandomGenerator
WHERE NOT EXISTS ( SELECT 1
FROM dbo.MyTable As excludeTbl
WHERE excludeTbl.MyPKColumn1 = RowNumber
AND excludeTbl.MyPKColumn2 = NextID )
至于你的问题(2),IGNORE_KEY_UP是一个索引选项。意思是,您只能在创建/更改索引时进行设置。根据“改变你的桌子”的意思,你有答案。从理论上讲,改变索引不会改变表格。 (注意唯一索引和主键不仅仅是索引。)
编辑:
考虑到你已经尝试了一下NOT EXISTS。我会告诉你,它存在3种方法来排除我所知道的值:NOT IN,NOT EXISTS,LEFT JOIN ON NULL VALUE。
在去IGNORE_KEY_UP之前,您应该尝试其中的3个。 IGNORE_KEY_UP随着时间的推移会给你带来很多问题。
LEFT JOIN ON NULL VALUE的示例:
INSERT INTO dbo.MyTable (MyPKColumn1, MyPKColumn2)
SELECT rg.RowNumber, rg.NextID
FROM dbo.RandomGenerator rg
LEFT JOIN dbo.MyTable mt
ON rg.RowNumber = mt.MyPKColumn1
AND rg.NextID = mt.MyPKColumn2
WHERE mt.MyPKColumn1 IS NULL
AND mt.MyPKColumn2 IS NULL
编辑2:
关于IGNORE_KEY_UP。哪里可能有问题?
他们有很多理由不使用IGNORE_KEY_UP,但我不是这个特殊原因的专家。我只能给你三个主要原因:
答案 1 :(得分:1)
我不确定我是否真的明白你想要的东西......
如果我做对了,你需要许多独特的随机数。以下代码将通过将NEWID()
的前4个字节强制转换为INT
来创建准随机列表。 ABS
会将反对的价值观变为正面。使用DISTINCT
没有重复的数字,这很快......
寻找100.000随机数,立即返回99.997。
DECLARE @Count INT=100000;
WITH
Tally(Nr) AS(SELECT TOP(@Count) ROW_NUMBER() OVER(ORDER BY(SELECT NULL)) FROM master..spt_values CROSS JOIN master..spt_values x CROSS JOIN master..spt_values y)
,Randoms(Rnd) AS(SELECT DISTINCT ABS(CAST(CAST(NEWID() AS VARBINARY(4)) AS INT)) FROM Tally)
SELECT ROW_NUMBER() OVER(ORDER BY (SELECT NULL))
,Rnd
FROM Randoms
您可以添加类似WHERE NOT EXISTS(SELECT 1 FROM YourTable WHERE ExistingCode=Rnd)
的内容,以确保返回的列表不包含现有数字...这样您就可以插入 as