Pregunta

Tenemos una tabla de usuarios, cada usuario tiene un correo electrónico y nombre de usuario único. Tratamos de hacer esto dentro de nuestro código, pero queremos estar seguros de que los usuarios nunca se insertan (o actualizados) en la base de datos con el mismo nombre de usuario de correo electrónico. He añadido un disparador BEFORE INSERT que impide la inserción de los usuarios duplicados.

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

Sin embargo, para el gatillo de actualización no tengo idea de cómo hacer esto. He encontrado este ejemplo con Google: http: // www .devarticles.com / c / a / SQL Server / Uso-Triggers-In-MS-SQL-servidor / 2 / Pero no sé si se aplica cuando se actualiza varias columnas a la vez.

EDIT:

He intentado añadir una restricción única en estas columnas, pero no funciona:

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.
¿Fue útil?

Solución

Se puede añadir un contraint único en la tabla, esto generará un error si intenta insertar o actualizar y crear duplicados

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

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

EDIT: Ok, acabo de leer sus comentarios a otro puesto y he visto que está utilizando NVARCHAR (MAX) como su tipo de datos. ¿Hay una razón por la cual es posible que desee más de 4000 caracteres para una dirección de correo electrónico o nombre de usuario? Aquí es donde radica el problema. Si se reduce esto a nvarchar (250) o por ahí, puede utilizar un índice único.

Otros consejos

suena como un montón de trabajo en lugar de usar uno o más índices únicos. ¿Hay alguna razón usted no ha ido por el camino índice?

¿Por qué no utilizar el atributo único en la columna en su base de datos? Ajuste que hará que el servidor SQL que cumplir y un error si se intenta insertar una víctima.

Se debe utilizar una restricción UNIQUE SQL en cada una de estas columnas para eso.

Se puede crear un UNIQUE INDEX en una NVARCHAR tan pronto como se trata de una NVARCHAR(450) o menos.

¿Usted realmente necesita una columna UNIQUE a ser tan grande?

En general, me volvería a evitar disparadores siempre que sea posible, ya que pueden hacer que el comportamiento muy difícil de entender a menos que sepa que existe el gatillo. Como otros han dicho commentatators, una restricción única es el camino a seguir (una vez que haya modificado sus definiciones de columna para que pueda).

Si alguna vez se encuentra la necesidad de usar un disparador, puede ser una señal de que su diseño es defectuoso. Pensar muy bien por qué lo necesita y si se está realizando lógica que pertenece a otra parte.

Tenga en cuenta que si utiliza la resolución de restricciones / índice único con SQL Server, se permitirá sólo un valor nulo en esa columna. Así, por ejemplo, si usted quiere la dirección de correo electrónico para ser opcional, no funcionaría, ya que sólo un usuario podría tener una dirección de correo electrónico nula. En ese caso, tendría que recurrir a otro enfoque como un disparador o un índice filtrado.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top