Consiglio su creazione indice.

6 views
Skip to first unread message

3st3b4n

unread,
Mar 9, 2005, 5:23:35 AM3/9/05
to
Ciao a tutti!

In una tabella ho un campo che inizialmente ha valore NULL ma poi, una volta
inserito un valore vorrei che questo valore non sia duplicato:

CREATE TABLE [dbo].[Utenti] (
[ID] [int] NOT NULL ,
[Nome] [char] (25) NOT NULL ,
[Cognome] [char] (25) NOT NULL ,
[UserID] [varchar] (50) NULL ,
[Password] [varchar] (50) NULL
) ON [PRIMARY]

CREATE UNIQUE INDEX [Utenti_IDX]
ON [dbo].[Utenti]([ID]) ON [PRIMARY]

INSERT Utenti (ID, Nome, Cognome)
VALUES (1, 'Esteban', 'Feros')

All'inserimento di un nuovo utente i campi [UserID] e [Password] hanno
valore NULL.
La prima volta che il nuovo utente esegue il login il programma richiede
l'inserimento di un UserID e di una Password per i login futuri. Chiaramente
il login non può essere uguale a quello di un altro utente inserito già
esistente e quindi pensavo di creare un indice sul campo [UserID]:

CREATE UNIQUE INDEX [Utenti_IDX2]
ON [dbo].[Utenti]([UserID]) ON [PRIMARY]

Il problema però è che aggiungendo un nuovo utente prima che l'ultimo utente
inserito abbia aggiornato il suo UserID:

INSERT Utenti (ID, Nome, Cognome)
VALUES (2, 'Etienne', 'Rouge')

mi viene segnalato l'errore che non è possibile aggiungere un nuovo record
in base all'indice Utenti_IDX2.

Certo, magari potrei fare a meno dell'indice ed ogni volta che un utente
vuole inserire / cambiare il proprio UserID potrei cercare nella tabella se
esiste già un utente con lo stesso UserID, però pensavo di poterlo fare con
un indice.

Avete da suggerirmi qualche soluzione?

Grazie!

--
3st3b4n
www.seber.it

Questo post è stato scritto con bit riciclati


Andrea Montanari

unread,
Mar 9, 2005, 5:41:25 AM3/9/05
to
salve,

3st3b4n wrote:
> Ciao a tutti!
>
> In una tabella ho un campo che inizialmente ha valore NULL ma poi,
> una volta inserito un valore vorrei che questo valore non sia
> duplicato:
>
> CREATE TABLE [dbo].[Utenti] (
> [ID] [int] NOT NULL ,
> [Nome] [char] (25) NOT NULL ,
> [Cognome] [char] (25) NOT NULL ,
> [UserID] [varchar] (50) NULL ,
> [Password] [varchar] (50) NULL
> ) ON [PRIMARY]
>...

personalmente aggiungerei anche ID alla definizione dell'indice,
CREATE UNIQUE INDEX [IX_utenti_UserId_Password] ON [dbo].[Utenti]
( [ID] , [UserID] , [Password] )
ON [PRIMARY]

saluti
--
Andrea Montanari (Microsoft MVP - SQL Server)
http://www.asql.biz/DbaMgr.shtm http://italy.mvps.org
DbaMgr2k ver 0.10.0 - DbaMgr ver 0.56.0
(my vb6+sql-dmo little try to provide MS MSDE 1.0 and MSDE 2000 a visual
interface)
--------- remove DMO to reply


Luca Bianchi

unread,
Mar 9, 2005, 5:51:28 AM3/9/05
to
3st3b4n wrote:
> Avete da suggerirmi qualche soluzione?

Un indice UNIQUE consente la presenza di un valore NULL (a differenza del
vincolo PK che non lo consente) ma può essere presente UN solo valore NULL
(e filosoficamente ci sarebbe da discutere), quindi è da escludersi questa
strada. In ogni caso la presenza di un indice (non unique) sul campo
faciliterebbe la ricerca di un eventuale valore duplicato eseguendo il
controllo nel momento in cui l'utente si registra. L'alternativa che mi
viene in mente è quella di inserire il record (quindi comprensivo di Nome e
Cognome) nel momento in cui effettua il primo logon oppure, in alternativa,
memorizzare le informazioni anagrafiche (Nome e Cognome) in una tabella e
quelle per l'accesso (UID e PWD) in un'altra relazionate per mezzo dell'ID.
Ad ogni modo mi viene da pensare che per poter informare l'utente che esiste
già un altro utente con la stessa UserID, devi comunque intercettare,
dall'applicazione, il codice di errore di chiave duplicata; a questo punto
sarebbe altrettanto agevole eseguire l'inserimento per mezzo di una stored
procedure che esegua il controllo di esistenza. Sto pensando ad una stored
procedure simile a

==========================
CREATE PROC dbo.FirstAccess
@id SMALLINT,
@uid VARCHAR(20),
@pwd VARCHAR(20)
AS

IF EXISTS (SELECT 1 FROM dbo.Utenti WHERE UserID = @uid)
RETURN -1

UPDATE dbo.Utenti
SET UserID = @uid,
Password = @pwd
WHERE ID = @id

RETURN 0
==========================

Testando quindi il valore di uscita della stored procedure puoi informare
l'utente che lo userid esiste già oppure che è stato accettato

> Grazie!

Bye

--
Luca Bianchi
Microsoft MVP - SQL Server
http://mvp.support.microsoft.com


Marcello

unread,
Mar 9, 2005, 5:52:29 AM3/9/05
to
Ciao,

puoi creare un vincolo di univocità su un sottoinsieme della tabella
sfruttando le viste indicizzate, per esempio una cosa del tipo

create table Utenti(id int identity,nome varchar(50), username
varchar(50), password varchar(50))
go
create view vi_Utenti with schemabinding
as
select username from dbo.utenti where not username is null
go
create unique clustered index IC on vi_Utenti(username)
go
drop view vi_Utenti
drop table Utenti

marc.

3st3b4n ha scritto:

3st3b4n

unread,
Mar 9, 2005, 5:52:44 AM3/9/05
to
Mentre mi apprestavo a riciclare alcuni bit, *Andrea Montanari* ha scritto:

> salve,
> 3st3b4n wrote:
>> Ciao a tutti!
>>
>> In una tabella ho un campo che inizialmente ha valore NULL ma poi,
>> una volta inserito un valore vorrei che questo valore non sia
>> duplicato:
>>
>> CREATE TABLE [dbo].[Utenti] (
>> [ID] [int] NOT NULL ,
>> [Nome] [char] (25) NOT NULL ,
>> [Cognome] [char] (25) NOT NULL ,
>> [UserID] [varchar] (50) NULL ,
>> [Password] [varchar] (50) NULL
>> ) ON [PRIMARY]
>> ...
>
> personalmente aggiungerei anche ID alla definizione dell'indice,
> CREATE UNIQUE INDEX [IX_utenti_UserId_Password] ON [dbo].[Utenti]
> ( [ID] , [UserID] , [Password] )
> ON [PRIMARY]

Intanto non metterei l'indice sulla password: non mi interessa se più di un
utente usa la stessa password. E poi che me ne faccio dell'indice sul campo
ID? Quello è sempre diverso e quindi due utenti che decidessero di usare la
stessa parola come UserID come farei a distinguerli al momento del login?

Andrea Montanari

unread,
Mar 9, 2005, 6:08:14 AM3/9/05
to
salve,

>> personalmente aggiungerei anche ID alla definizione dell'indice,
>> CREATE UNIQUE INDEX [IX_utenti_UserId_Password] ON [dbo].[Utenti]
>> ( [ID] , [UserID] , [Password] )
>> ON [PRIMARY]
>
> Intanto non metterei l'indice sulla password: non mi interessa se più
> di un utente usa la stessa password. E poi che me ne faccio
> dell'indice sul campo ID? Quello è sempre diverso e quindi due utenti
> che decidessero di usare la stessa parola come UserID come farei a
> distinguerli al momento del login?

l'aggiunta della colonna [ID] consente di mantenere l'unicita' anche a
livello di NULL sugli altri 2 attributi (NULL al momento della generazione)
della riga.. e giustamente e' sempre diverso in quanto unico per ogni
utente...ma giustamente ti complichi la vita nella gestione dell'unicita'
del binomio userid/password
per la validazione sull'unicita' della sola UserID, mantenendo il disegno
attuale, devi invece procedere come indicato da Luca.. in effetti la sua
soluzione di inserire un valore di default derivante dalle altre colonne del
predicato .. e meglio ancora avere una relazione separata..

3st3b4n

unread,
Mar 10, 2005, 1:26:21 AM3/10/05
to
Mentre mi apprestavo a riciclare alcuni bit, *Luca Bianchi* ha scritto:

>> Avete da suggerirmi qualche soluzione?
>

Ho optato per questa soluzione. Grazie per il suggerimento.

Reply all
Reply to author
Forward
0 new messages