La adición de una restricción para evitar duplicados en SQL activador de actualización
-
23-08-2019 - |
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.
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.