Unieke data in je database zetten
Op het forum worden veel vragen gesteld over het uniek maken van bepaalde velden. Zo wil je bijvoorbeeld maar 1 dezelfde gebruikersnaam hebben, of maar 1 email adres. Er zijn nog meer redenen, maar daar ga ik nu even niet op in.
Veel gebruikte, slechte manier
Een veel gehoord antwoord/oplossing op deze vraag is:
1
2
3
4
5
6
|
Draai een select query op de database
Kijk naar aantal resultaten
Als resultaat = 1
Fout
Als resultaat = 0
Voeg data in
|
|
|
Een twee eenvoudige query's, die op het eerste oog niks fout doen.
Waarom is dit fout dan?
Je kan
nooit zeker weten dat op deze manier je data uniek is. Stel twee gebruikers maken een account aan, op het moment dat zij de select-query draaien is de naam nog uniek.
Gebruiker 1 voegt vervolgens zijn username in en gebruiker 2 doet dit ook. Nu is de data niet meer uniek en is je database in principe waardeloos geworden.
Een optie zou zijn om dit in transactions te doen of om de tabel te locken. Maar je houd nog steeds 1 nutteloze query over.
Maar het kan nog eenvoudiger
In je database kun je key's instellen en aan deze key's kun je eisen stellen. Bijvoorbeeld primaire key maar ook een unique key. Laten we dit ook gaan doen.
We maken bijvoorbeeld een user tabel met heel eenvoudig:
1
2
3
4
5
6
7
8
|
CREATE TABLE `tuts`.`unique_users` (
`user_id` INT NOT NULL AUTO_INCREMENT PRIMARY KEY ,
`username` VARCHAR( 50 ) NOT NULL ,
`password` VARCHAR( 32 ) NOT NULL ,
UNIQUE (
`username`
)
) ENGINE = InnoDB;
|
|
|
We hebben nu een veld wat uniek moet zijn (eigenlijk 2, een primary key moet ook uniek zijn).
Vervolgens voeren we de volgende query uit:
1
2
3
4
5
6
7
8
|
INSERT INTO `tuts`.`unique_users` (
`user_id` ,
`username` ,
`password`
)
VALUES (
NULL , 'foo', MD5( 'bar' )
);
|
|
|
We hebben nu een user met de naam foo. Als we onze query nog een keertje draaien krijgen we het volgende resultaat:
1
2
|
mysql_errno(); #1062
mysql_error(); #Duplicate entry 'foo' for key 'username'
|
|
|
En nu verder?
Jeee, we hebben nu een foutmelding. Het zou wel erg handig zijn als we de user op een normale manier kunnen vertellen dat zijn geliefde gebruikersnaam al in gebruik is.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
|
$result = mysql_query("
INSERT INTO `tuts`.`unique_users` (
`user_id` ,
`username` ,
`password`
)
VALUES (
NULL , 'foo', MD5( 'bar' )
);
");
if( !$result && mysql_errno() == 1062 )
{
echo 'Deze gebruikersnaam bestaat al';
}
elseif( $result )
{
echo 'Je bent nu lid';
}
else
{
echo 'Er trad een andere fout op';
}
|
|
|
Het lijkt meer werk dan dat het is. Maar uiteindelijk heb je constistente data en bespaar je weer een query
Mocht je meerdere unieke velden hebben, zoals een emailadres. Vis dan gewoonweg het veld uit de error-string en geef daarbij een mooie foutmelding.
Unieke combinatie
Ook een heel mooi voordeel van deze techniek is dat je eenvoudig een combinatie van velden uniek kan maken (en houden). Je hebt bijvoorbeeld een nieuwsite waarbij een bericht wordt gekenmerkt door de slug en de datum.
1
2
3
4
5
6
7
|
CREATE TABLE `tuts`.`unique_news` (
`postdate` DATE NOT NULL ,
`slug` VARCHAR( 255 ) NOT NULL
) ENGINE = InnoDB;
-- En nog een mooie index:
ALTER TABLE `tuts`.`unique_news` ADD UNIQUE `uniek_bericht` ( `postdate` , `slug` ) -- zou eigenlijk PRIMARY moeten zijn. Maar is ter indicatie
|
|
|
Nu nog wat testdata
1
2
3
4
5
6
7
8
9
|
INSERT INTO `tuts`.`unique_news` (
`postdate` ,
`slug`
)
VALUES (
'2010-10-06', 'foto-van-de-dag'
), (
'2010-10-07', 'foto-van-de-dag'
);
|
|
|
Tot nu toe gaat alles goed, de combinatie datum en slug is uniek. Maar als we op 7/10/2010 nog een foto van de dag toevoegen krijgen we weer een fout
1
|
Duplicate entry '2010-10-06-foto-van-de-dag' for key 'uniek_bericht'
|
|
|
Dit klopt ook, want er was op die dag al een bericht geplaatst met die slug.
Ik hoop dat je door deze tutorial weer wat opgeschoten bent. Mocht je nog vragen hebben stel ze in het forum of in de reacties. (Mail, PM of msn beantwoord ik niet, dit is een forum en mensen kunnen van elkaar leren)
Tim
ps. Mocht het op deze manier wat onoverzichtelijk zijn dan plaats ik het wel in pagina's. Maar het leek me niet zo veel.