2009-02-13 93 views
0

我們有一個用戶表,每個用戶都有一個唯一的電子郵件和用戶名。我們嘗試在我們的代碼中執行此操作,但我們希望確保用戶不會使用相同的電子郵件用戶名在數據庫中插入(或更新)。 我添加了一個BEFORE INSERT觸發器,它可以防止插入重複的用戶。添加約束以防止SQL更新中的重複觸發

CREATE TRIGGER [dbo].[BeforeUpdateUser] 
    ON [dbo].[Users] 
    INSTEAD OF INSERT 
AS 
BEGIN 
    -- SET NOCOUNT ON added to prevent extra result sets from 
    -- interfering with SELECT statements. 
    SET NOCOUNT ON; 

    DECLARE @Email nvarchar(MAX) 
    DECLARE @UserName nvarchar(MAX) 
    DECLARE @UserId int 
    DECLARE @DoInsert bit 

    SET @DoInsert = 1 

    SELECT @Email = Email, @UserName = UserName FROM INSERTED 

    SELECT @UserId = UserId FROM Users WHERE Email = @Email 

    IF (@UserId IS NOT NULL) 
     BEGIN 
      SET @DoInsert = 0 
     END 

    SELECT @UserId = UserId FROM Users WHERE UserName = @UserName 

    IF (@UserId IS NOT NULL) 
     BEGIN 
      SET @DoInsert = 0 
     END 

    IF (@DoInsert = 1) 
     BEGIN 
      INSERT INTO Users 
      SELECT 
          FirstName, 
          LastName, 
          Email, 
          Password, 
          UserName, 
          LanguageId, 
          Data, 
          IsDeleted 
         FROM INSERTED 
     END 
    ELSE 
     BEGIN 
      DECLARE @ErrorMessage nvarchar(MAX) 
      SET @ErrorMessage = 
         'The username and emailadress of a user must be unique!' 
      RAISERROR 50001 @ErrorMessage 
     END 
END 

但是對於更新觸發器,我不知道如何做到這一點。 我發現這個例子與谷歌: http://www.devarticles.com/c/a/SQL-Server/Using-Triggers-In-MS-SQL-Server/2/ 但我不知道它是否適用於一次更新多個列。

編輯:

我試圖在這些列上添加唯一約束,但它不工作:

Msg 1919, Level 16, State 1, Line 1 
Column 'Email' in table 'Users' is of a type 
that is invalid for use as a key column in an index. 
+0

這個問題真的不好冠軍。這個問題沒有關於更新觸發器以及如何使列獨一無二的問題。這個問題不會幫助任何人搜索SQL Update觸發器。 – CodeMonkey 2013-02-06 12:09:46

回答

12

您可以在表中添加獨特的contraint,這將引發一個錯誤,如果你嘗試插入或更新,並創建副本

ALTER TABLE [Users] ADD CONSTRAINT [IX_UniqueUserEmail] UNIQUE NONCLUSTERED 
(
    [Email] ASC 
) 

ALTER TABLE [Users] ADD CONSTRAINT [IX_UniqueUserName] UNIQUE NONCLUSTERED 
(
    [UserName] ASC 
) 

編輯:好吧,我剛剛看了你的意見,另一篇文章並看到您正在使用NVARCHAR(MAX)作爲您的數據類型。是否有一個原因,您可能需要超過4000個字符的電子郵件地址或用戶名?這是你的問題所在。如果將其減少到NVARCHAR(250)或其附近,則可以使用唯一索引。

4

聽起來像很多工作,而不是僅僅使用一個或更獨特的索引。你有沒有走過索引路線的原因?

+0

你確定嗎?我很確定你可以。 – 2009-02-13 14:33:06

+0

你確定嗎?我只是試過這個SQL 2005對我來說很好看 – JoshBerke 2009-02-13 14:35:25

1

爲什麼不在數據庫的列上使用UNIQUE屬性?設置這將使SQL服務器強制執行並拋出錯誤,如果你試圖插入一個愚蠢的。

1

您應該在這些列的每一列上使用SQL UNIQUE約束。

0

只要是NVARCHAR(450)或更低,您就可以在NVARCHAR上創建UNIQUE INDEX

你真的需要一個UNIQUE列這麼大嗎?

+0

不要相信他們,他們說謊。 – Quassnoi 2009-02-13 15:24:51

0

一般而言,我會盡可能地避免觸發器,因爲除非知道觸發器的存在,否則它們會使行爲非常難以理解。正如其他評論者所說,唯一的約束是要走的路(一旦你修改了列定義來允許它)。

如果您發現自己需要使用觸發器,這可能表示您的設計存在缺陷。仔細想想你爲什麼需要它,以及它是否在執行屬於別處的邏輯。

0

請注意,如果您對SQL Server使用UNIQUE約束/索引解決方案,則該列中只允許有一個空值。因此,例如,如果您希望電子郵件地址是可選的,則它不起作用,因爲只有一個用戶可能具有空電子郵件地址。在這種情況下,你將不得不採用另一種方法,如觸發器或過濾索引。