使用触发器确保唯一性

时间:2012-08-28 14:55:31

标签: sql-server sql-server-2008 triggers

所以,我正在尝试使用以下触发器,以便在更新表中的行时,它会将特定列设置为包含8个随机字母数字字符的字符串。触发器工作正常,但结果必须是唯一的。在触发器之前它将是空白的,因此服务器上不会强制执行此唯一性。这个想法是,一旦客户在一个过程中足够远,他们就会得到这个字符串,但之前没有,因为我们得到了大量没有那么远的客户。

触发器:

CREATE TRIGGER test_rand
ON test_trigger
AFTER UPDATE 
AS
    UPDATE test_trigger set col2=(select
    Random_String =
    substring(x,(abs(checksum(newid()))%36)+1,1)+
    substring(x,(abs(checksum(newid()))%36)+1,1)+
    substring(x,(abs(checksum(newid()))%36)+1,1)+
    substring(x,(abs(checksum(newid()))%36)+1,1)+
    substring(x,(abs(checksum(newid()))%36)+1,1)+
    substring(x,(abs(checksum(newid()))%36)+1,1)+
    substring(x,(abs(checksum(newid()))%36)+1,1)+
    substring(x,(abs(checksum(newid()))%36)+1,1)

from
          (select x='0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ') a) WHERE col2=''; 
GO

此触发器是我使用只有两列col1col2的简单表格运行的测试。我为一堆行更新了col1col2得到了看似随机的值,但我知道两行可以得到相同的数字,如果可能的话我想阻止它。

我原本想过在select语句中检查一下这个字符串不存在但是我还没有找到一个好的方法来做到这一点。

我是触发器的新手,所以如果有一些简单的东西我缺失或应该被搜索过,那么我为浪费你的时间而道歉。对于我所知道的人来说,这甚至可能都不可能,但我想在放弃并尝试别的东西之前我应该​​问一下。

此外,在执行更新的脚本中没有完成此操作的原因是我无法从客户端获得关于实际执行此操作的脚本的直接答案。如果这是不可能的,我只会编写一个由Windows任务计划程序运行的任务,但我希望这样做。

我的解决方案

根据我们告诉我的内容,我创建了以下代码,它完成了我想要的任务:

CREATE TRIGGER test_rand
ON test_trigger
AFTER UPDATE 
AS
    DECLARE @Ins_Col3 int;
    DECLARE Ins_Curs CURSOR FOR SELECT col3 FROM inserted;
    DECLARE @Ref char(8);

    OPEN Ins_Curs

    FETCH NEXT FROM Ins_Curs
    INTO @Ins_Col3;

    WHILE @@FETCH_STATUS = 0
    BEGIN;
        SET @Ref = LEFT(NEWID(), 8);

        WHILE(EXISTS(SELECT col2 from test_trigger WHERE col2=@Ref))
        BEGIN;
            SET @Ref = LEFT(NEWID(), 8);
        END;

        UPDATE test_trigger SET test_trigger.col2=@Ref FROM inserted WHERE test_trigger.col3=@Ins_Col3;
            FETCH NEXT FROM Ins_Curs
        INTO @Ins_Col3;
    END;

我必须将col3添加为自动递增的id值,以便我可以识别每一行。 因此col1仅在那里,因此我可以通过更新声明进行更改。

2 个答案:

答案 0 :(得分:2)

您应该使用GUID而不是kludging 8 char字符串。在SQL Server中,它是UniqueIdentifier列类型。这是一篇关于它的文章:http://msdn.microsoft.com/en-us/library/ms190215(v=sql.105).aspx

答案 1 :(得分:0)

如果您想防止这种情况发生,请在触发器中包含WHILE循环,只要生成的字符串由于违反唯一性条件而无效就会循环:

WHILE 0=0
BEGIN
 SET_TO_NEW_VALUE
 IF(NEW_VALUE_IS_UNIQUE)
  BREAK
END

如果值不唯一,您还可以ROLLBACKRAISEERROR。取决于你想要发生的事情。