Vincolo ceck?

mercoledì 08 marzo 2006 - 18.31

alex1962 Profilo | Newbie

Salve a tutti,mi chiamo alex e sono di firenze mi sono registrato or ora e ho subito un problemino da porre.
Sono autodidatta su sql 2000 e perciò le mie conoscenze sono limitate. Ho un db legato ad una applicazione in asp con diverse tabelle e una di queste mi crea non pochi problemi.
Mi spiego meglio:
un campo char da 10 dove ho messo un valore di default con '00000000' nel caso lo lascino vuoto.
adesso vorrei mettere anche un vincolo che se erratamente mettono in quel campo valori diversi da 8 caratteri mi metta automaticamente '00000000'
il problema è che non so come fare...... con una regola? un vincolo? un dato predefinito dall'utente?
boh
buona serata
alex

lbenaglia Profilo | Guru

>Salve a tutti,mi chiamo alex e sono di firenze mi sono registrato
>or ora e ho subito un problemino da porre.

Ciao Alex,

benvenuto su DotNetHell

>un campo char da 10 dove ho messo un valore di default con '00000000'
>nel caso lo lascino vuoto.
>adesso vorrei mettere anche un vincolo che se erratamente mettono
>in quel campo valori diversi da 8 caratteri mi metta automaticamente
>'00000000'
>il problema è che non so come fare...... con una regola? un vincolo?
>un dato predefinito dall'utente?
>boh

Allora, fammi capire: una colonna char(10) con un default di 8 zeri... se mi mettono un numero diverso da 8 caratteri allora voglio rimettere 8 zeri... direi che è una richiesta piuttosto insolita.
Prima di tutto ti suggerisco di modificare il data type da char(10) a varchar(10) altrimenti "butti via" 2 bytes per tutte le righe che hanno quella colonna valorizzata con una stringa di 8 caratteri.
Inoltre, perché permetti di inserire 10 caratteri se poi imponi come limite una lunghezza massima di 8 caratteri? Boh...

Cominciamo a capire che compito svolgono i vari vincoli:

Un constraint default, beh, dato che l'utilizzi hai già capito a cosa serve, cioè a valorizzare automaticamente una colonna con il valore impostato se durante una operazione di INSERT non è stato specificato alcun valore oppure se è stata utilizzata la keyword DEFAULT in corrispondenza di quella colonna;
un constraint di tipo check serve per verificare se il valore assegnato ad una colonna soddisfa una determinata espressione specificata nella definizione del constraint stesso (ad esempio che la quantità deve essere > di 0);
una rule (regola) è funzionalmente identica ad un constraint ma è un oggetto proprietario di SQL Server e non aderisce allo standard ANSI SQL-92, pertanto non andrebbe utilizzata.

Allora come fare? In questo caso ti suggerirei di ricorrere ad un trigger.
Un trigger può essere inteso come una particolare stored procedure che viene eseguita ogni qualvolta si inserisce, aggiorna o elimina una riga in una tabella.
All'interno di un trigger hai la possibilità di accedere alle tabelle virtuali [inserted] e [deleted] che contengono rispettivamente le righe inserite e cancellate da un comando DML (INSERT, DELETE, UPDATE).
Il comando di UPDATE lo puoi interpretare come una DELETE seguita da una INSERT, pertanto la tabella [deleted] conterrà il precedente valore della riga, mentre la tabella [inserted], il nuovo.

OK, dopo questa brevissima (ed incompleta ) definizione di trigger, vediamo come implementare la tua richiesta.
Osserva il seguente esempio:

USE tempdb; GO /* Definisco la tabella dbo.Students */ CREATE TABLE dbo.Students( StudentID int NOT NULL IDENTITY, FirstName varchar(10) NOT NULL, LastName varchar(10) NOT NULL, City char(10) NOT NULL DEFAULT '00000000', CONSTRAINT PK_Students PRIMARY KEY(StudentID) ); GO /* Definisco il trigger tr_IU_Students */ CREATE TRIGGER tr_IU_Students ON dbo.Students FOR INSERT, UPDATE AS SET NOCOUNT ON; IF UPDATE(City) BEGIN UPDATE dbo.Students SET City = DEFAULT FROM dbo.Students AS S JOIN inserted AS I ON S.StudentID = I.StudentID WHERE LEN(I.City) <> 8 END; GO /* Ora andiamo a popolare la tabella: ** queste 3 righe verranno inserite tali e quali dato che ** la colonna City è stata valorizzata con una stringa di ** esattamente 8 caratteri */ INSERT dbo.Students VALUES('Lorenzo', 'Benaglia', '12345678'); INSERT dbo.Students VALUES('Luca', 'Bianchi', 'aaaaaaaa'); INSERT dbo.Students VALUES('Andrea', 'Montanari', 'bbbbbbbb'); /* Queste invece non soddisfano la logica implementata nel ** trigger e pertanto avranno la colonna City valorizzata ** con il suo valore di default */ INSERT dbo.Students VALUES('Gianluca', 'Hotz', '123'); INSERT dbo.Students VALUES('Andrea', 'Benedetti', '1234567890'); GO /* Ovviamente il tutto funzionerà anche inserendo più righe ** contemporaneamente */ INSERT dbo.Students SELECT 'David', 'De Giacomi', 'cccccccc' -- valido UNION ALL SELECT 'Ester', 'Memoli', 'dddddddd' -- valido UNION ALL SELECT 'Andrea', 'Benedetti', 'ee' -- non valido UNION ALL SELECT 'ObiWan', 'Kenobi', 'ffffffff' -- valido GO /* Vediamo... */ SELECT * FROM dbo.Students; GO /* Output: StudentID FirstName LastName City ----------- ---------- ---------- ---------- 1 Lorenzo Benaglia 12345678 2 Luca Bianchi aaaaaaaa 3 Andrea Montanari bbbbbbbb 4 Gianluca Hotz 00000000 5 Andrea Benedetti 00000000 6 David De Giacomi cccccccc 7 Ester Memoli dddddddd 8 Andrea Benedetti 00000000 9 ObiWan Kenobi ffffffff (9 row(s) affected) */ /* Infine aggiorniamo qualche riga */ UPDATE dbo.Students SET City = 'gggg' -- non valido WHERE StudentID = 1 GO UPDATE dbo.Students SET City = 'hhhhhhhh' -- valido WHERE StudentID = 4 GO /* Vediamo... */ SELECT * FROM dbo.Students; GO /* Output: StudentID FirstName LastName City ----------- ---------- ---------- ---------- 1 Lorenzo Benaglia 00000000 2 Luca Bianchi aaaaaaaa 3 Andrea Montanari bbbbbbbb 4 Gianluca Hotz hhhhhhhh 5 Andrea Benedetti 00000000 6 David De Giacomi cccccccc 7 Ester Memoli dddddddd 8 Andrea Benedetti 00000000 9 ObiWan Kenobi ffffffff (9 row(s) affected) */ /* Pulizia */ DROP TABLE dbo.Students;

Come puoi notare, prima di tutto verifico se è stata modificata la colonna City da una operazione di INSERT o UPDATE, dopo di che effetto una inner join tra la tabella base e la tabella inserted valorizzando la colonna City con il suo valore di default per tutte le righe che non rispettano la regola degli 8 caratteri.
Spero che sia chiaro

Se lo desideri puoi approfondire l'argomento Triggers sui Books Online:

"Enforcing Business Rules with Triggers"
http://msdn.microsoft.com/library/en-us/createdb/cm_8_des_08_116g.asp

"CREATE TRIGGER"
http://msdn.microsoft.com/library/en-us/tsqlref/ts_create2_7eeq.asp


>buona serata
Anche a te.

Ciao!

--
Lorenzo Benaglia
Microsoft MVP - SQL Server
http://blogs.dotnethell.it/lorenzo/
http://italy.mvps.org

alex1962 Profilo | Newbie

grazie lorenzo, ho materiale per incasinarmi la vita per un bel pò di ore

Ti volevo chiedere ancora 1 cosa:
perche nel thread c'è la voce"accetta la risposta"? a cosa serve?
alex

lbenaglia Profilo | Guru

>grazie lorenzo, ho materiale per incasinarmi la vita per un bel
>pò di ore

Divertiti

>Ti volevo chiedere ancora 1 cosa:
>perche nel thread c'è la voce"accetta la risposta"? a cosa serve?

Se ritieni che una risposta risponda adeguatamente alla domanda, puoi "votarla" in modo da segnalare che il tizio che ha risposto è "un gallo", facendogli guadagnare qualche punticino per risalire la classifica dei "personaggi affidabili" (un po' quello che succede su ebay).

Ciao!

--
Lorenzo Benaglia
Microsoft MVP - SQL Server
http://blogs.dotnethell.it/lorenzo/
http://italy.mvps.org
Partecipa anche tu! Registrati!
Hai bisogno di aiuto ?
Perchè non ti registri subito?

Dopo esserti registrato potrai chiedere
aiuto sul nostro Forum oppure aiutare gli altri

Consulta le Stanze disponibili.

Registrati ora !
Copyright © dotNetHell.it 2002-2024
Running on Windows Server 2008 R2 Standard, SQL Server 2012 & ASP.NET 3.5