Aggiunta di un vincolo per impedire duplicati in SQL Update Trigger
-
23-08-2019 - |
Domanda
Abbiamo una tabella utenti, ogni utente ha un'e-mail e un nome utente univoci.Cerchiamo di farlo all'interno del nostro codice ma vogliamo essere sicuri che gli utenti non vengano mai inseriti (o aggiornati) nel database con lo stesso nome utente dell'email.Ho aggiunto un BEFORE INSERT
Trigger che impedisce l'inserimento di utenti duplicati.
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
Ma per il trigger di aggiornamento non ho idea di come farlo.Ho trovato questo esempio con Google:http://www.devarticles.com/c/a/SQL-Server/Using-Triggers-In-MS-SQL-Server/2/Ma non so se si applica quando aggiorni più colonne contemporaneamente.
MODIFICARE:
Ho provato ad aggiungere un vincolo univoco su queste colonne ma non funziona:
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.
Soluzione
È possibile aggiungere un contraint univoco nella tabella, tale da far salire un errore se si tenta di inserire o aggiornare e creare duplicati
ALTER TABLE [Users] ADD CONSTRAINT [IX_UniqueUserEmail] UNIQUE NONCLUSTERED
(
[Email] ASC
)
ALTER TABLE [Users] ADD CONSTRAINT [IX_UniqueUserName] UNIQUE NONCLUSTERED
(
[UserName] ASC
)
EDIT: Ok, ho appena letto i vostri commenti ad un altro posto e visto che si sta utilizzando NVARCHAR (MAX) come tipo di dati. C'è un motivo per cui si potrebbe desiderare di più di 4000 caratteri per un indirizzo email o nome utente? Questo è dove il vostro problema. Se si riduce questo per NVARCHAR (250) o giù di lì, allora è possibile utilizzare un indice univoco.
Altri suggerimenti
Sembra molto lavoro invece di utilizzare solo uno o più indici univoci.C'è un motivo per cui non hai seguito il percorso dell'indice?
Perché non usare l'attributo univoco per la colonna nel database? Impostazione che renderà il server SQL far rispettare questo e genera un errore se si tenta di inserire una vittima.
Si dovrebbe usare un vincolo di SQL UNIQUE
su ciascuna di queste colonne per questo.
È possibile creare un UNIQUE INDEX
su un NVARCHAR
non appena si tratta di un NVARCHAR(450)
o meno.
Avete veramente bisogno di una colonna UNIQUE
per essere così grande?
In generale, vorrei evitare trigger per quanto possibile in quanto possono rendere il comportamento molto difficile da capire se non sai che esiste il grilletto. Come altri commentatators hanno detto, un vincolo univoco è la strada da percorrere (una volta che avete modificato i vostri definizioni di colonna per permettergli).
Se mai trovate a dover utilizzare un trigger, può essere un segno che il vostro disegno è viziata. Riflettere sul perché avete bisogno e se si sta eseguendo logica che appartiene altrove.
Si noti che se si utilizza la soluzione di vincolo / indice UNIQUE con SQL Server, un solo valore nullo sarà permesso in quella colonna. Così, per esempio, se si voleva l'indirizzo e-mail per essere opzionale, non funzionerebbe, perché solo un utente potrebbe avere un indirizzo di posta elettronica nullo. In tal caso, si dovrà ricorrere ad un altro approccio, come un trigger o un indice filtrato.