2012-08-28 33 views
1

所以,我試圖使用下面的觸發器,以便當表中的某行更新時,它會將一個特定列設置爲一個由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='ABCDEFGHIJKLMNOPQRSTUVWXYZ') a) WHERE col2=''; 
GO 

這個觸發器是我用一個簡單的表格,只有有兩列,col1col2運行測試。我更新了col1一堆行,col2獲得了看似隨機的值,但是我知道兩行可以獲得相同的數字,如果可能,我想阻止它。

我曾經想過在select語句本身做一個檢查,該字符串不存在,但我一直沒有想出一個好的方法來做到這一點。

我是新來的觸發器,所以如果有簡單的東西我失蹤或應該已經搜查,然後我道歉浪費你的時間。這可能對我所知的所有人都是不可能的,但我想我應該在放棄和嘗試別的之前先問一下。

此外,在更新的腳本中沒有完成的原因是我無法從客戶端獲得直接回答,因爲哪些腳本實際執行該操作。如果這是不可能的,我會寫一個任務由Windows任務計劃程序運行,但我希望能夠這樣做。

我的解決方案

基於斷什麼USR告訴我,我已經創建了下面的代碼,做了什麼,我想:

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 [email protected])) 
     BEGIN; 
      SET @Ref = LEFT(NEWID(), 8); 
     END; 

     UPDATE test_trigger SET [email protected] FROM inserted WHERE [email protected]_Col3; 
      FETCH NEXT FROM Ins_Curs 
     INTO @Ins_Col3; 
    END; 

我不得不添加col3作爲一個自增ID值,以便我可以識別每一行。 col1因此只有這樣才能使用更新語句更改某些內容。

+0

你的代碼應該可以工作,但我不確定你可以從GUID的前八個字節獲得一個隨機數有多好。見http://blogs.msdn.com/b/oldnewthing/archive/2008/06/27/8659071.aspx –

+0

我認爲你應該嘗試與你的客戶談談使用UniqueIdentifier字段。 NEWID()函數總是會給你一個唯一的字符串。您將獲得性能提升,因爲您不會試圖確保您的價值已不在數據庫中。 UniqueIdentifier只有128位。您的八字符字段至少爲64位。額外的64位性能提升值得。 –

+0

但這不是關於表演。這是關於讓客戶使用這種方式來識別推薦他們的人,而客戶並不認爲再讓他們打字或寫下來可能會造成問題。這也適用於測試系統,甚至可能持續超過一個月或兩個月。如果他們決定保持更長的時間,那麼我可能會與他們討論延長它的時間。 – sparrow

回答

0

如果你想避免這種情況發生,包括在你的觸發一個WHILE環,只要生成的字符串是無效的,由於違反了惟一性條件循環:

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

您也可以ROLLBACK和如果該值不唯一,則爲RAISEERROR。取決於你想要發生的事情。

+0

問題是,不止一行可能會一次觸發此內容,所以如果我按照您的建議做了他們將獲得相同的值,除非有一種方法可以遍歷受我更新影響的所有行一直無法找到。 – sparrow

+0

您可以迭代使用INSERTED和DELETED僞表影響的所有行。您可以使用遊標對它們進行迭代,也可以使用update語句對它們進行批量分配。 – usr

+0

這就是我已經完成的。如果其他人想看到它,我會在問題中發佈完成的代碼。 – sparrow

2

您應該使用GUID而不是拼湊8個字符串。在SQL Server中,它是一個UniqueIdentifier列類型。這裏有一篇關於它的文章:http://msdn.microsoft.com/en-us/library/ms190215(v=sql.105).aspx

+0

我希望我可以使用,但我不認爲我可以。如果我已經正確地閱讀鏈接,爲了確保UniqueIdentifier是唯一的,我需要將該約束添加到該行。但是,我需要允許該列爲NULL,直到發生操作,這違反了約束。我可以與客戶交談,看看他們是否可以改變,但我可以使用它。感謝您指出這一點,因爲我的谷歌搜索沒有改變這一點。 – sparrow

+0

UniqueIdentifier值保證始終爲唯一值。你是正確的,列中的唯一約束不允許兩行爲空。 (在這一點上,Oracle比SQL Server更好)。也許你可以在UniqueIdentifier列中始終有一個值,並使用另一列來表示你想要的空值的任何值?或者可能相信UniqueIdentifier是唯一的? (這將是)。 –

+0

我只是重新閱讀我鏈接的文章。除非您放置約束,否則它們指定UniqueIdentifier值cab的部分會多次出現,這需要更多的說明。他們所說的是,如果您的應用程序代碼獲得GUID值,則可以根據需要將該單個GUID值插入到多個行中。這篇文章並不是說你插入一個後可能會意外地得到重複的GUID值。 NEWID函數或獲取新GUID的appcode返回的值將始終是唯一的。 –