Ovo je bre najbolja zabava na celom forumu
Zaboravio sam da kazem - student moze imati jedan i samo jedan MinistryNumber. Chachka je absolutno u pravu kad kaze da u tabeli koju je Dejan dodao treba oba polja da budu unique. Moj komentar na to isto je potpuno pogresan - ako zahtevamo da kombinacija (StudenID, MinistryNumber) bude unique, onda upravo dozvoljavamo da ima bezbroj takvih kombinacija. Zurio sam da krenem kuci, pa isma mislio sta lupetam.
@negixo: Hvala za view, to je jos jedno moguce resenje koje lepo izgleda. U pravu si za komentar izracunatog polja, nismo ga resili onako kako sam napisao, zurba opet. Nas stvarni slucaj bio je malo drukciji, studentNumber bilo je char(9), samo cifre 0 do 9 dozvoljene, pa su za NULL stavili nesto kao 'A' + CAST(StudentUID as varchar). Ja sam dao primer sa StudentNumber INT, pa sam morao na brzinu da izmisljam resenje. Tvoja ideja se negatvnim StudentUID je prava stvar. Mi smo mogli da upotrebimo i samo StudentUID, jer nam je ministryNumber sa 9 cifara, > 600 000 000, a StudentId je jos uvek na 6 cifara, i raste brzinom od oko 500,000 godisnje, pa bi sve radilo lepo dvadesetak godina barem.
Da rezimiramo:
Zadatak:
Code:
(
StudentID, int, PK,
MinistryNumber int, NULL dozvoljene, ako nije NULL mora biti UNIQUE
ostala polaj
)
Resenje 1 (Milos Bajic), moze u sistemima koji ignorisu NULL vrednosti pri postavljanju unuique constraints: creirati unique constraint/index po polju MinistryNumber
Resenje 2 (Dejan Toplaovic i Chachka), radi u svim sistemina: promeniti model, razbiti tabelu na dve i dovesti ih u vezu 1:1
Code:
CREATE TABLE Students (
StudentID INTEGER NOT NULL PRIMARY KEY
);
CREATE TABLE MinistredStudents (
StudentID INTEGER NOT NULL PRIMARY KEY REFERENCES Students,
MinistryNumber INTEGER NOT NULL UNIQUE
);
CREATE VIEW AllAboutStudents (
StudentID,
MinistryNumber)
AS
SELECT s.StudentID, ms.MinistryNumber
FROM Students AS s
LEFT OUTER JOIN
MinistredStudents AS ms
ON s.StudentID = ms.StudentID;
Resnje 3, (Negyxo), indexirani view, radi naravno u sistemima koji podrzavaju indexirani view:
Code:
SET NUMERIC_ROUNDABORT OFF
SET ANSI_PADDING ON
SET ANSI_WARNINGS ON
SET CONCAT_NULL_YIELDS_NULL ON
SET ARITHABORT ON
SET QUOTED_IDENTIFIER ON
SET ANSI_NULLS ON
GO
CREATE VIEW dbo.VStudent WITH SCHEMABINDING
AS
SELECT
CASE
WHEN minID IS NULL THEN studentID * 18446744073709551616
ELSE minID
END AS uniqueMinistryKey
FROM
dbo.Student
Code:
CREATE UNIQUE CLUSTERED INDEX UK_MinID
ON VStudent(uniqueMinistryKey)
Moja opaska: view je mogao biti i jednostavniji, na primer
Code:
CREATE VIEW dbo.VStudent WITH SCHEMABINDING
AS
SELECT MinistryKey
FROM Student
WHERE MinistryKey IS NOT NULL -- ovim eliminisemo NULL vrednosti iz viewa
CREATE UNIQUE CLUSTERED INDEX UK_MinID
ON VStudent(uniqueMinistryKey)
Resenje 4 (Chachka) , cisto SQL, po standardu koji nazalost ni jedan sistem osim Firebird ne podrzava:
Code:
CREATE TABLE Students
(
StudentID INTEGER NOT NULL PRIMARY KEY,
MinistryNumber INTEGER
CHECK ( (MinistryNumber IS NULL)
OR (NOT MinistryNumber IN (SELECT MinistryNumber
FROM Students
WHERE NOT MinistryNumber IS NULL
)
)
)
);
Deo koji nije podrzan je upotreba SELECTu CHECK constraint.
Resenje 5, po idejy Negyxo, resili Zidarevi programeri na slican nacin, uvodjenjem calculated column:
Code:
MyCalcColumn =
CASE
WHEN minID IS NULL THEN -studentID --- negativan StudentID
ELSE minID
END
pa se doda unique constraint na ovu kolonu. Negativan StudentID garantuje da se nece pomesati vrednosti iz dve kolone. Ako je kolona MinistryNumber varchar tipa, onda se jedinstvenost postize dodavanjem prefixa na CAST(StudentID as varchar), bilo kakvog, koji ce povecati duzinu stringa i tako ga uciniti razlicitim od bilo kog regularnog MinsitryNumber.
Naravno, ostaje resenje sa trigerima, ali cemu triger kad imamo ovoliki izbor dobrih resenja?
Koje je resenje najbolje? Zavisi od toga sta imate. U Accessu i PostgreSQL ocigledno je najbolje (u Accesu i jedino moguce) resenje ono oprvo, sa indeksom. Verujem da ekipa koja ima te mogucnosti ne moze da se nacudi o kakvim nebulozama mi ovde pricamo....
Licno bih izabrao ono za Firebird, ali nazalost ne radi za sada nigde drugo. Potom bih izabrao ono sa razbijanjem tabele na dve i relcijom 1:1. Malo je i iskusnih profesionalaca koji bi se drznuli da ovako razmisljaju, zaboga, kakva je to relacija 1:1, u skoli nas uce da postoji (1:vise) i (vise : jos vise)

)
Zasto mi nismo isli na razbijanje tabele? Kolona MinistryNumber je naknadno dodata originalnom modelu, posle 3-4 godine u produkciji, a problem jedinstvenosti se pojavio nekoliko meseci posle dodavanja kolone, kad se ispostavilo da uprkos uveravanju ekipe iz minstarstva obrazovanja, postoje studenti koji nemaju MinistryNumber. Da stvar bude jos gora, saznali smo naknadno da to nije sve. Postoje tri vrste studenta:
- oni koji imaju MinistryNumber (mora biti jedinstven)
- oni koji ga nemaju, ali ce ga dobiti u buducnosti (emigranti tek prispeli u zemlju, doseljeni kanadjani iz druge provincije)
- oni koji ga nikad nece imati (idu u specijalne privetne skole koje ne rade po drzavniom programima). Oni svi imaju vrednost '000 000 000' (razmaci su samo da se lakse cita, u kolonu ide bez razmaka'
Ovo poslednje nas je nateralo da idemo sa kalkulisanom kolonom. Sva resenja, i koja volimo i koja ne volimo ,na neki nacin odvajaju NULL vrednosti od non-NULL vrednosti. A sta da radimo sa gomilom '000 000 000'? Najjeftinije je bilo da uradimo izracnato polje, ovako:
Code:
MyCalcColumn =
CASE
WHEN (MinistryNumberIS NULL)
OR (MinistryNumber = 0) --- ovo je dodatni uslov, dodacemo jos ako treba
THEN -studentID --- negativan StudentID
ELSE MinistryNumberIS
END
Ovu izracunatu kolonu korsnici niti vide, niti znaju za nju. Svi objekti u bazi i van nje ostali su isti , stored procedures, aplikacije na front endu, absolutno nista se nije promenilo. I ako nam ubace neki novi uslov, dodacemo novi OR/AND u formulu za izracunatu kolonu.
Bas su ove NULL vrednosti nezgodna stvar, zar ne
Ja sam verovatno najstariji po godinama ovde, ali mi to ne daje za pravo da samo ja postavljam mozgalice. Primeri iz prakse su dobrodosli.
Tema nije zatvorena, ako neko im jos neko resenje, sa zadovoljstvom cemo ga prihvatiti.
Hvala svima na trudu.
Edit: Dodati su kod tagovi.
[Ovu poruku je menjao chachka dana 02.09.2007. u 01:56 GMT+1]