Voorbeeld HTML-PHP-PostgreSQL

Simpele Handleiding om met HTML-PHP-PostgreSQL een website te maken waarmee je informatie kunt beheren in een (PostgreSQL) Database en deze via HTML (en PHP) weer kunt tonen en kunt aanpassen.

Wat gaan wij doen:

Deze pagina laat zien hoe je een Web-Site kunt maken met HTML, PHP en een PostgreSQL database-systeem.
We gaan een simpel systeem maken waarin je de volgende informatie kunt bijhouden: Voornaam, Achternaam en E-mailadres.
Bezoekers van deze website zullen in staat zijn deze adresgegevens toe te voegen en informatie uit dit systeem op te vragen, en te wijzigen en ook weer te verwijderen (als u dat wilt).
De informatie in dit systeem zal worden opgeslagen in een PostgreSQL-Database. Deze Database wordt bestuurt door PHP, welke op zijn beurt en onderdeel is van uw HTML-Pagina waardoor de informatie zichtbaar kan worden gemaakt aan de website bezoeker.

Hoe gaan we het doen:

We gaan dit stap voor stap doen op een manier die het mogelijk maakt dat u als het ware mee doet en dus iets creeert wat ook zou werken. U gaat daadwerkelijk rechtstreeks werken op/met de computer (unix/linux (internet) webserver) waarop deze website moet gaan lopen.

Gebruikte Lettertypes:

In deze voorbeeld handleiding wordt een speciaal lettertype (en tekst kleur) gebruikt om aan te geven welke tekst de computer aan u op de terminal toont en hetgeen u dient in te typen (zie voorbeeld regel hieronder):

Dit is tekst dat de computer u toont: en dit moet u typen.

Toegang tot unix/linux (web) server/computer

We gaan er van uit dat u toegang hebt tot een (unix/linux) systeem met daarop een (apache) Webserver, PHP (scripttaal)en PostgreSQL (databasesysteem).
U bezit dus een unix user-id en een bijbehorend wachtwoord.
(als voorbeeld gebruiken we als unix-User-id: uxuserid met wachtwoord: uxwachtwoord.)
En u bent ook in het bezit van een PostgreSQL user-id en wachtwoord.
(als voorbeeld gebruiken we als PostgreSQL-User-id: pguserid met wachtwoord: pgwachtwoord.)
Deze dient u dus te vervangen door uw eigen betreffen User-id's en wachtwoorden.

Hoe typen we??

In unix dient u na elke regel op de [Enter] of [Return] toets drukken om aan te geven dat deze regel gereed is (u dus klaar bent met typen). In dit voorbeeld geef ik niet aan waar u op Enter moet drukken, gewoon als de regel klaar is drukt u op Enter.

Aanloggen:

U dient aan te loggen aan het unix-systeem via een telnet sessie

(het wachtwoord is niet zichtbaar als u het intypt):

Login: uxuserid
uxuserid@mkux400's password:        
SSH: Access granted!
#####################################################################
#                                                                   #
#     Toegang alleen toegestaan voor ge-authoriseerde gebruikers    #
#     welke alleen door de beheerder toegestaane werkzaamheden      #
#     mogen uitvoeren.                                              #
#                                                                   #
#     Niet ge-autoriseerde toegang zal worden bestraft !!!          #
#     Toegang en uitgevoerde werkzaamheden worden gelogd!!          #
#                                                                   #
# Users who do not understand the Dutch language are not allowed !! #
#                                                                   #
#####################################################################

uxuserid   pts/1        Mon Apr 25 18:14   still logged in    gateway.lan

wtmp begins Fri Apr  1 16:24:47 2005
[uxuserid@mkux400 uxuserid]$

U bent nu aan unix aangelogd en unix is gereed om uw commando's uit te voeren.

PostgreSQL:

Database Ontwerp

Verbinding maken met het database-systeem

Nu gaan we eerst de tabel maken waarin de informatie moet komen te staan. Deze tabel komt onder het database-systeem te staan, dus we gaan eerst hier aan aanloggen:
Op de shell-prompt (zie het $ - tekentje op het scherm) geeft u het volgende commando: psql
(ook hier is het wachtwoord niet zichtbaar als u het intypt):

[uxuserid@mkux400 uxuserid]$ psql
Password: 
Welcome to psql, the PostgreSQL interactive terminal.
Type:  \copyright for distribution terms
       \h for help with SQL commands
       \? for help on internal slash commands
       \g or terminate with semicolon to execute query
       \q to quit
pguserid=>

Het systeem heeft (automatisch) aangenomen dat de unix-userid gelijk is aan het PostgreSQL userid.
Indien u dit niet wilt kunt dit ook specificeren met: psql <database> <userid>, waarbij u <database> vervangt door de gewenst database-naam en <userid> door het userid waarmee u wilt werken, zoals in ons geval:

[uxuserid@mkux400 uxuserid]$ psql pguserid pguserid
Password:

U bent nu aan PostgreSQL aangelogd en PostgreSQL is gereed om uw commando's uit te voeren. (PostgreSQL heeft u een aantal handige commando's gegeven, ga hier eens me spelen om te zien wat er achter zit. U bevindt zich in uw eigen persoonlijke database (zeg maar een stuk schijfruimte) welke wordt beheerd door het database-systeem.

Eerste Commando's

Alle tabellen opvragen:

Als eerst kunt u het commando: \dt geven om te zien welke tabellen (dit kunt u vergelijken met kleine kaartenbakjes) er in uw persoonlijke database zijn:

pguserid=> \dt
No relations found.
pguserid=>

Als er geen tabellen zijn zag u het bovenstaande, zijn er wel tabellen aanwezig dan ziet u bv. dit:

pguserid=> \dt
        List of relations
     Name     | Type  |  Owner
--------------+-------+----------
 deelnemers   | table | pguserid
 organisator  | table | pguserid
 verenigingen | table | pguserid
(3 rows)

pguserid=>

Tabel maken

Nu gaan we de voorbeeld-tabel aanmaken. In deze tabel komt dus de volgende informatie te staan:
Voornaam, Achternaam en e-mail adres.
Deze informatie als geheel noemen we in database-spreektaal een record of row (rij).

Uniek veld (kolom)

Nu is het verstandig om elk record in een tabel een unieke identificatie te geven zodat we later een record uniek kunnen opvragen. Deze unieke identificatie kan bv. zijn PostCode + Huisnummer, of zoals in ons voorbeeld gewoon een nummer. Voor ons eigen gemak maken we gebruik van de mogelijkheid dat het database-systeem zelf een uniek nummer toekent aan elk record dat wordt toegevoegd (waarom het verstandig is om een veld (kolom) te gebruiken waarin een unieke code komt te staan zal verderop in een voorbeeld duidelijk worden gemaakt). U bent niet verplicht om een nummer als unieke identificatie te gebruiken. Wat u ook gebruikt, er moet een mogelijkheid zijn om elk record in de tabel uniek aan te kunnen wijzen. Het is ook mogelijk om een zogenaamde 'index' aan te maken die er voor zorgt dat de gespecificeerde velden in de tabel uniek blijven.

Te gebruiken velden (kolommen)

We hebben nu dus de volgende informatie nodig voor onze tabel: uniek-nummer, voornaam, achternaam en e-mail-adres.
In database-termen worden deze informatie-eenheden 'fields' (velden of kolommen) genoemd, en we zullen ze nu een handige naam moeten geven, bv.
uniek-nummer wordt veld: nummer,
voornaam wordt veld: voornaam,
achternaam wordt veld: achternaam en
e-mail-adres wordt veld: e_mail.

Tabel definitie

We moeten ook nog aangeven wat voor velden het zijn, zoals tekst velden, nummerieke velden enz.
Veld 'nummer' is een nummeriek veld (in ons geval een auto-increment of serial veld)
Veld 'voornaam' is een tekst veld met een lengte (maximaal) van 12 letters,
Veld 'achternaam' is een tekst veld met een lengte (maximaal) van 30 letters en
Veld 'e_mail' is een tekst veld met een lengte (maximaal) van 50 letters.

De naam van de tabel waarin we deze informatie gaan opslaan noemen we: voorbeeldtabel.
We hebben nu voldoende informatie om de tabel voorbeeldtabel te maken en daarin velden te definieren.
Dit gaat dmv. SQL-Commando's. Hiervan zijn er vele aanwezig. In de loop van dit voorbeeld-systeem zult u er vele leren kennen en toepassen.
Het eerste SQL-Comando dat we gaan gebruiken is het CREATE TABLE commando.

(In SQL moet u een SQL-Commando afsluiten met een ';', hiermee geeft u aan dat het SQL-Commando nu gereed is om uit gevoerd te worden. Hierdoor is het mogelijk om zeer grote SQL-Commando's in te typen die meerdere regels lang zijn. Uw SQL Commando zal pas NA de ';' worden uitgevoerd.)

Het (volledige) SQL-commando wat we hier moeten gaan geven om de genoemde tabel aan te maken is:

create table SQl-Commando:

create table voorbeeldtabel
(nummer serial ,
voornaam char(12) ,
achternaam char(30) ,
e_mail char(50)
);

Het volgende verschijnt:

pguserid=> create table voorbeeldtabel
pguserid-> (nummer serial ,
pguserid(>  voornaam char(12) ,
pguserid(>  achternaam char(30) ,
pguserid(>  e_mail char(50)
pguserid(> );
NOTICE:  CREATE TABLE will create implicit sequence 'voorbeeldtabel_nummer_seq' for SERIAL column 'voorbeeldtabel.nummer'
NOTICE:  CREATE TABLE / UNIQUE will create implicit index 'voorbeeldtabel_nummer_key' for table 'voorbeeldtabel'
CREATE
pguserid=>

Het commando \d (ipv. \dt) zal nu bv. het volgende laten zin:

pguserid=> \d
              List of relations
           Name            |   Type   | Owner
---------------------------+----------+-------
 voorbeeldtabel            | table    | pguserid
 voorbeeldtabel_nummer_seq | sequence | pguserid
(2 rows)

pguserid=>

De tabel (sequence): voorbeeldtabel_nummer_seq is een tabel die er voor zorgt dat het veld nummer altijd een unieke waarde bevat. U kunt deze (extra) tabel verder vergeten in het normale gebruik, maar onthoudt dat hij er wel is, bv. als u de tabel voorbeeldtabel weggooit zult u ook de voorbeeldtabel_nummer_seq expliciet moeten weggooien.
Deze (Sequence) tabel: voorbeeldtabel_nummer_seq bevat een index die er voor zorgt dat het veld 'nummer' altijd unieke waarden bevat. Een dergelijke index kunt u ook zelf aanmaken.

We hebben nu een tabel met de naam voorbeeldtabel met daarin de genoemde velden. Maar is dit wel zo??, we gaan eens opvragen wat er in de tabel voorbeeldtabel zit.
Hiertoe geven we een ander (ons tweede) SQL-Commando, en wel een commando dat in 90% van de gevallen zal worden gebruikt, het SELECT-commando (om alles in een keer op te vragen typ: select * from voorbeeldtabel;):

Gegevens opvragen uit de tabel
pguserid=> select * from voorbeeldtabel;
 nummer | voornaam | achternaam | e_mail
--------+----------+------------+--------
(0 rows)

pguserid=>

Wow, we hebben iets, maar verder ook niet.. (De kolomen zijn aanwezig, maar er is (nog) geen informatie aanwezig, we hadden alles op gevraagd en 0 rijen gekregen..)

Record toevoegen aan tabel

Hieraan moeten we iets doen, we gaan een derde SQL-Commando gebruiken: het INSERT INTO commando.
We gaan de volgende informatie in de tabel opnemen:
uw voornaam, uw achternaam en uw e-mail adres.
Het SQL-commando hiervoor is:
insert into voorbeeldtabel (voornaam,achternaam,e_mail)
values('uw voornaam','uw achternaam','uw e-mail adres') ;

pguserid=> insert into voorbeeldtabel (voornaam,achternaam,e_mail)
pguserid-> values('uw voornaam','uw achternaam','uw e-mail adres');
INSERT 24977 1
pguserid=>
Uitleg Insert ( en Update/Delete) SQL-Commando antwoorden:

Nadat u het insert-commando gaf kreeg u het volgende antwoord van PostgreSQL: INSERT 24977 1
Hiermee geeft PostgreSQL aan wat het effect van uw commando is geweest. Het was een INSERT-commando, (het grote getal: 24977, welke alleen bij een INSERT wordt getoont, kunt u vergeten/overslaan), en er werd 1 record toegevoegd (een commando kan namelijk ook tot gevolg hebben dat er veel meer dan 1 item tegelijk gewijzigd kan worden). Het grote getal kan soms met grote sprongen omhoog gaan, dit komt omdat u niet de enige gebruiker van een PostgreSQL-database bent, maar dat er ook andere gebruikers zijn die INSERT's uitvoeren.

Opvraag niewe record

Indien we nu weer alles gaan opvragen (middels het SQL-Commando: select * from voorbeeldtabel; ) zien we het volgende:

pguserid=> select * from voorbeeldtabel;
 nummer |   voornaam   |           achternaam           |                       e_mail
--------+--------------+--------------------------------+----------------------------------------------------
      1 | uw voornaam  | uw achternaam                  | uw e-mail adres
(1 row)

pguserid=>

Zoals u kunt zien staat uw ingetype naam nu werkelijk in de tabel (uw database) en heeft het ook daadwerkelijk een nummer gekregen. Maar 1 rij is wel een beetje weinig vindt u ook niet, vandaar dat we er nog twee (als voorbeeld) gaan toevoegen. (U mag natuurlijk zelf naar hartelust meerdere namen (rijen/records) toevoegen, dit voorbeeldsysteem gaat echter in eerste instantie uit van deze 3 rijen):

insert into voorbeeldtabel (voornaam,achternaam,e_mail)
values('Martie','Krukkeland','martiekr@worldonline.nl') ;

insert into voorbeeldtabel (voornaam,achternaam,e_mail)
values('De Laatste','Derde Achternaam','En nog een E-mail adres') ;

pguserid=> insert into voorbeeldtabel (voornaam,achternaam,e_mail)
pguserid-> values('Martie','Krukkeland','martiekr@worldonline.nl') ;
INSERT 24978 1
pguserid=> insert into voorbeeldtabel (voornaam,achternaam,e_mail)
pguserid-> values('De Laatste','Derde Achternaam','En nog een E-mail adres') ;
INSERT 24979 1

Nu gaan we natuurlijk ook weer even kijken wat het inmiddels is geworden
(weer met het SQL-Commando: select * from voorbeeldtabel; )

pguserid=> select * from voorbeeldtabel;
 nummer |   voornaam   |           achternaam           |                       e_mail
--------+--------------+--------------------------------+----------------------------------------------------
      1 | uw voornaam  | uw achternaam                  | uw e-mail adres
      2 | Martie       | Krukkeland                     | martiekr@worldonline.nl
      3 | De Laatste   | Derde Achternaam               | En nog een E-mail adres
(3 rows)

pguserid=>

Hoe zit een INSERT INTO command in elkaar:

Het commando ziet er ongeveer (simpel voorgestelt) zo uit:
INSERT INTO <TabelNaam>
(Veldenlijst, gescheiden door een komma)
VALUES(<de Waarden in de betreffende Velden>,<Ook gescheiden door een Komma>) ;

Onze tabel heeft de volgende velden: voornaam,achternaam,e_mail , deze noemen we dus in de Veldenlijst. U hoet ze niet allemaal op te noemen, velden die u niet noemt krijgen geen waarde en zullen dus 'leeg' zijn na het invoegen van de rij.
U mag ook elke willekeurige veldenvolgorde aanhouden, dit maakt niets uit, echter bedenk wel dat de juiste data in het gewenste veld komt..
Hierna komt de VALUES (waarden) opdacht die opgeeft bepaald welke waarde er in het betreffende veld moet komen te staan. de waarden voor teks-velden zet u ALTIJD tussen quotjes, nummerieke velden zijn gewoon het getal. U kunt een getal plaatsen in een tekst-veld door het dus tussen quotjes te zetten. Een tekst in een nummeriek veld zetten gaat niet.
U mag SQL-Commando ook met een gerust hart over meerdere regels uitschrijven, dit maakt PostgreSQL niets uit:

insert
into
voorbeeldtabel
(
voornaam,
achternaam,
e_mail
)
values
(
'aaaaa',
'bbbb',
'ccccc'
)
;

werkt ook, dus:

pguserid=> insert
pguserid-> into
pguserid-> voorbeeldtabel
pguserid-> (
pguserid(> voornaam,
pguserid(> achternaam,
pguserid(> e_mail
pguserid(> )
pguserid-> values
pguserid-> (
pguserid(> 'aaaaa',
pguserid(> 'bbbb',
pguserid(> 'ccccc'
pguserid(> )
pguserid-> ;
INSERT 24980 1

is perfect, we hebben nu dus 4 records (rijen)..

pguserid=> select * from voorbeeldtabel;
 nummer |   voornaam   |           achternaam           |                       e_mail
--------+--------------+--------------------------------+----------------------------------------------------
      1 | uw voornaam  | uw achternaam                  | uw e-mail adres
      2 | Martie       | Krukkeland                     | martiekr@worldonline.nl
      3 | De Laatste   | Derde Achternaam               | En nog een E-mail adres
      4 | aaaaa        | bbbb                           | ccccc
(4 rows)

pguserid=>

Nu gaan we een beetje spelen met de SQL-Commando SELECT.
De SQL-SELECT Commano's noemen we Query's (Vragen aan een Database-Systeem). SQL betekend: Structured Query Language. SQL is dus een Vraag-Taal..
We gaan eerst bv. opvragen welke voornamen er in onze tabel zitten, dit doen we met: select voornaam from voorbeeldtabel ; )

pguserid=> select voornaam from voorbeeldtabel ;
   voornaam
--------------
 uw voornaam
 Martie
 De Laatste
 aaaaa
(4 rows)

pguserid=>

Nu hebben we ipv. het sterretje ('*') een veldnaam gevraagt, hetgeen dus betekend dat een '*' ALLE velden tegelijk is.
Zou dit ook werken: select nummer,achternaam from voorbeeldtabel; ?

pguserid=> select nummer,achternaam from voorbeeldtabel ;
 nummer |           achternaam
--------+--------------------------------
      1 | uw achternaam
      2 | Krukkeland
      3 | Derde Achternaam
      4 | bbbb
(4 rows)

pguserid=>

Ja dus, dit werkt ook. Nu gaan we nog een stap verder, ik wil niet alles zien, maar ik wil alleen het e-mail adres zien van 'Martie' (=voornaam). Dit kan met het SQL-Commando: select e_mail from voorbeeldtabel where voornaam = 'Martie' ;
het volgende kan natuurlijk ook om korte regels te houden en een overzichtelijk SQL-Commando te krijgen:
select e_mail
from voorbeeldtabel
where voornaam = 'Martie' ;

pguserid=> select e_mail
pguserid-> from voorbeeldtabel
pguserid-> where voornaam = 'Martie' ;
                       e_mail
----------------------------------------------------
 martiekr@worldonline.nl
(1 row)

pguserid=>

Dit zijn nog maar enkele simpele voorbeelden, wist u dat een SQL-Commando meer honderden regels lang kan zijn, een dergelijk Commando zijn informatie uit meerdere tabellen tegelijk kan halen, en uiteindelijk berekent hoeveel winst er gemaakt??.

Een voorbeeld van een groot SQL-SELECT commando;

Hieronder staat een voorbeeld van een dergelijk groot SQL-SELECT Commando. Deze gebruik ik (Martie) in een Concours-Programma (om de organisatie van een paarden/ponies Concours-Hippique te kunnen automatiseren) om in een keer de Verenigingen-Lijst te kunnen afdrukken met alle relevante gegevens, gegroepeert per VerenigingNummer. Het maakt binnen de SELECT weer gebruik van Sub-Query's (die op zich zelf ook weer SQL-SELECT-Commando's zijn), een van deze sub-query's heet bv.: DressuurTweedeKosten, deze sub-query berekent bv. de kosten van de tweede dressuurproef van een bepaalde deelnemer. Tevens maakt het gebruik van 2 tabellen: Deelnemers en Verenigingen. De Sub-Query's zelf maken ook gebruik van een aantal andere tabellen oa.: VraagProgramma en Uitslagen (bevat ook starttijden) om de aanvullen informatie te kunnen leveren (Kosten en Starttijdstippen).

SELECT " & _
   Deelnemers.CombiNr, Deelnemers.DeelnemerNr, Deelnemers.DoetMee, 
   Deelnemers.DlnmrNaam , Deelnemers.RijdierNaam,Deelnemers.VerenigingNr, 
   Deelnemers.EersteDressuurProef, Deelnemers.EersteDressuurProefSpec, 
   Deelnemers.EersteDressuurRubriek, Deelnemers.TweedeDressuurProef, 
   Deelnemers.TweedeDressuurProefSpec, Deelnemers.TweedeDressuurRubriek, 
   Deelnemers.EersteSpringProef, Deelnemers.EersteSpringProefSpec, 
   Deelnemers.EersteSpringRubriek, Deelnemers.TweedeSpringProef, 
   Deelnemers.TweedeSpringProefSpec, Deelnemers.TweedeSpringRubriek, 
   Deelnemers.OverigeKosten, Deelnemers.BetaaldBedrag, Deelnemers.ProefKosten, 
   Deelnemers.CouponsIngeleverd , Deelnemers.Catagorie, 
   Verenigingen.VerenigingNr as VerenigingNr, Verenigingen.Ver_Afk, 
   Verenigingen.VerenigingNaam, Verenigingen.VerenigingPlaats, 
   Verenigingen.ContactNaam, Verenigingen.ContactAdres, 
   Verenigingen.ContactPostCode, Verenigingen.ContactPlaatsNaam, 
   Verenigingen.KomtVanVer, 
   DressuurEersteKosten.Proefnaam, DressuurEersteKosten.DeelnameKosten, 
   DressuurTweedeKosten.Proefnaam, DressuurTweedeKosten.DeelnameKosten, 
   SpringEersteKosten.Proefnaam, SpringEersteKosten.DeelnameKosten, 
   SpringTweedeKosten.Proefnaam, SpringTweedeKosten.DeelnameKosten , 
   iif(DressuurEersteKosten.DeelnameKosten>0,DressuurEersteKosten.DeelnameKosten,0) + 
   iif(DressuurTweedeKosten.DeelnameKosten>0,DressuurTweedeKosten.DeelnameKosten,0) + 
   iif(SpringEersteKosten.DeelnameKosten>0,SpringEersteKosten.DeelnameKosten,0) + 
   iif(SpringTweedeKosten.DeelnameKosten>0,SpringTweedeKosten.DeelnameKosten,0) as DlnTot,
   DressuurEersteTijdstip.Tijdstip, DressuurTweedeTijdstip.Tijdstip,
   SpringEersteTijdstip.Tijdstip, SpringTweedeTijdstip.Tijdstip
FROM
  ((((((((
   Deelnemers
       LEFT JOIN Verenigingen ON Deelnemers.VerenigingNr = Verenigingen.VerenigingNr)
       LEFT JOIN DressuurEersteKosten   ON Deelnemers.EersteDressuurProef = DressuurEersteKosten.ProefNaam)
       LEFT JOIN DressuurTweedeKosten   ON Deelnemers.TweedeDressuurProef = DressuurTweedeKosten.ProefNaam)
       LEFT JOIN SpringEersteKosten     ON Deelnemers.EersteSpringProef = SpringEersteKosten.ProefNaam)
       LEFT JOIN SpringTweedeKosten     ON Deelnemers.TweedeSpringProef = SpringTweedeKosten.ProefNaam)
       LEFT JOIN DressuurEersteTijdstip ON (Deelnemers.EersteDressuurRubriek = DressuurEersteTijdstip.Rubriek) AND
                                           (Deelnemers.DeelnemerNr = DressuurEersteTijdstip.DeelnemerNr))
       LEFT JOIN DressuurTweedeTijdstip ON (Deelnemers.TweedeDressuurRubriek = DressuurTweedeTijdstip.Rubriek) AND 
                                           (Deelnemers.DeelnemerNr = DressuurTweedeTijdstip.DeelnemerNr))
       LEFT JOIN SpringEersteTijdstip   ON (Deelnemers.EersteSpringRubriek = SpringEersteTijdstip.Rubriek) AND 
                                           (Deelnemers.DeelnemerNr = SpringEersteTijdstip.DeelnemerNr))
       LEFT JOIN SpringTweedeTijdstip   ON (Deelnemers.TweedeSpringRubriek = SpringTweedeTijdstip.Rubriek) AND 
                                           (Deelnemers.DeelnemerNr = SpringTweedeTijdstip.DeelnemerNr)
WHERE DOETMEE;

Dit soort grote query's zult u waarschijnlijk nooit hoeven te maken, maar u kunt nu zien wat er mogelijk is. (Ik ga ook niet proberen om uit te leggen waarom dit SQL-Commando doet wat het moet doen, dit zou op zich al voldoende informatie opleveren om een boek te schrijven over het maken van SQL-Queries en die zijn wel te vinden in de bibliotheek. Bovenstaande query is trouwens gemaakt dmv. de SQL-Query-wizard in Ms-Access die de basis legde en daarna handmatig aangevult om bovenstaande te verkrijgen daar de Ms-Access (97) wizard niet krachtig genoeg is om dit te kunnen maken ..)

Zoals u hiervoor hebt kunnen lezen zou ik nog uitleggen waarom het zeer aan te bevelen is om elke tabel te voorzien van een kolom waarin een waarde kan worden geze die elk record een unieke identificatie geeft.
Hiertoe gaan we eerst een record toevoegen die ongeveer lijkt op ons laatse record (4):

insert into voorbeeldtabel (voornaam,achternaam,e_mail) values('ababa','bbbb','ccccc');

pguserid=> insert into voorbeeldtabel (voornaam,achternaam,e_mail) values('ababa','bbbb','ccccc');
INSERT 33162 1
pguserid=>

Nu gaan we de records opvragen waarbij we bewust aannemen dat we geen unieker (nummer) kolom hebben. :

pguserid=> select voornaam,achternaam,e_mail from voorbeeldtabel;
   voornaam   |           achternaam           |                       e_mail
--------------+--------------------------------+----------------------------------------------------
 uw voornaam  | uw achternaam                  | uw e-mail adres
 Martie       | Krukkeland                     | martiekr@worldonline.nl
 De Laatste   | Derde Achternaam               | En nog een E-mail adres
 aaaaa        | bbbb                           | ccccc
 ababa        | bbbb                           | ccccc
(5 rows)

pguserid=>

We hebben nu dus 5 records, en we doen net dat we een fout gaan verbeteren en nemen dus aan dat de voornaam van 'aaaaa' had moeten zijn: 'ababa' en de het e_mail adres van 'ababa' moet 'ddddd' worden. We geven dus de volgende SQL-Update commando's:
update voorbeeldtabel set voornaam='ababa' where voornaam='aaaaa';
update voorbeeldtabel set e_mail='ddddd' where voornaam='ababa';

pguserid=> update voorbeeldtabel set voornaam='ababa' where voornaam='aaaaa';
UPDATE 1
pguserid=> update voorbeeldtabel set e_mail='ddddd' where voornaam='ababa';
UPDATE 2
pguserid=> select voornaam,achternaam,e_mail from voorbeeldtabel;
   voornaam   |           achternaam           |                       e_mail
--------------+--------------------------------+----------------------------------------------------
 uw voornaam  | uw achternaam                  | uw e-mail adres
 Martie       | Krukkeland                     | martiekr@worldonline.nl
 De Laatste   | Derde Achternaam               | En nog een E-mail adres
 ababa        | bbbb                           | ddddd
 ababa        | bbbb                           | ddddd
(5 rows)

pguserid=>

Bij de tweede update zag u al iets vreemd, er werden 2 records tegelijk gewijzigd, terwijl er dus maar 1 gewijzigd had moeten worden. Na de select is duidelijk waarom: de eerste Update veranderde de voornaam in 'ababa', waardoor er nu dus 2 voornamen 'ababa' in de tabel aanwezig zijn (de nieuwe en de oude) en de tweede update dus alle twee de records gebruikt om het e_mail adres te wijzigen. Hoe kunnen we er nu voor zorgen dat we bij SQL-Command's deze laatste 2 records (rijen) weer verschillend zijn?? Hiervoor is een truukje, met een aangepaste SQL-Opdracht kunt u regel dat u de wijzigingen/selects alleen op bv. het eerste record uitvoert, maar dit zou te ver voeren om te behandelen, wil je het weten, vraag het dan gewoon aan mij (er is bijvoorbeeld een SQL LIMIT parameter)..

Om dit soort problemen te voorkomen moet u dus een kolom in een tabel opnemen waarin een nunieke waarde komt te staan:

pguserid=> select * from voorbeeldtabel;
 nummer |   voornaam   |           achternaam           |                       e_mail
--------+--------------+--------------------------------+----------------------------------------------------
      1 | uw voornaam  | uw achternaam                  | uw e-mail adres
      2 | Martie       | Krukkeland                     | martiekr@worldonline.nl
      3 | De Laatste   | Derde Achternaam               | En nog een E-mail adres
      5 | ababa        | bbbb                           | ddddd
      4 | ababa        | bbbb                           | ddddd
(5 rows)

pguserid=>

Om te testen voegen we nog een record toe:

pguserid=> insert into voorbeeldtabel (voornaam,achternaam,e_mail) values('ababa','bbbb','ccccc');
INSERT 33163 1
pguserid=> select * from voorbeeldtabel;
 nummer |   voornaam   |           achternaam           |                       e_mail
--------+--------------+--------------------------------+----------------------------------------------------
      1 | uw voornaam  | uw achternaam                  | uw e-mail adres
      2 | Martie       | Krukkeland                     | martiekr@worldonline.nl
      3 | De Laatste   | Derde Achternaam               | En nog een E-mail adres
      5 | ababa        | bbbb                           | ddddd
      4 | ababa        | bbbb                           | ddddd
      6 | ababa        | bbbb                           | ccccc
(6 rows)

pguserid=>

Nu is het wel makkelijk, want de kolom 'nummer' is ALTIJD uniek, dus het simpel weggooien van de laatste rij doen we met: delete from voorbeeldtabel where nummer=6 ;

pguserid=> delete from voorbeeldtabel where nummer=6;
DELETE 1

pguserid=>

En weer opvragen wat we nu over hebben:

pguserid=> select * from voorbeeldtabel;
 nummer |   voornaam   |           achternaam           |                       e_mail
--------+--------------+--------------------------------+----------------------------------------------------
      1 | uw voornaam  | uw achternaam                  | uw e-mail adres
      2 | Martie       | Krukkeland                     | martiekr@worldonline.nl
      3 | De Laatste   | Derde Achternaam               | En nog een E-mail adres
      5 | ababa        | bbbb                           | ddddd
      4 | ababa        | bbbb                           | ddddd
(5 rows)

pguserid=>

In bovenstaande voorbeelden hebben we ook al even kort gewerkt met de SQL-UPDATE en SQL-DELETE opdrachten. Deze opdrachten brengen wijzigingen (UPDATE) aan in de tabel of verwijderen reocrds uit de tabel (DELETE).
Bij de UPDATE vertelt u welke velden welke nieuwe waarde moeten krijgen waarbij de WHERE vertelt welke records (rijen) deze wijzigingen moeten krijgen.
Bij de DELETE vertelt u weer via de WHERE welke rijen er verwijderd moeten worden. Dus bij de SELECT, UPDATE en DELETE is de WHERE heel belangrijk, hiermee geeft u aan welke rijen er betrokken moeten worden bij het commando.
Als u zou besluiten de WHERE niet te gebruiken zou uw opdracht betrekking hebben op de gehele tabel!!

Hoe zit een DELETE FROM command in elkaar:

Het DELETE commando is het eenvoudigst: DELETE FROM<TabelNaam> WHERE <Welke Records> ;
Of zoals we hierboven bv. al hebben gezien met het verwijderen van Record Nummer 6:

pguserid=> delete from voorbeeldtabel where nummer=6;
DELETE 0
pguserid=>

"DELETE 0"?? Oh ja, we hadden hem al weggegooit, dus nu 0 records (rijen) verwijderd (Nummer 6 bestond al niet meer).

Hoe zit een UPDATE command in elkaar:

Bij een UPDATE gaan we dus eerste vertellen welke velden welke nieuwe waarde moeten krijgen, en daarna weer de WHERE, dus een update is:
UPDATE <tabelNaam> SET <VeldNaam1>=<NieuweWaarde1> WHERE <Welke Records>.
UPDATE <tabelNaam> SET <VeldNaam1>=<NieuweWaarde1>,<VeldNaam2>=<NieuweWaarde2>, enz WHERE <Welke Records>.
Dus als we record nummer 5 willen updaten, zodat de VoorNaam wordt: 'aaaaa' en het e_mail adres moet worden: 'ccccc', dan kunnen we dit met een UPDATE-commando doen of met twee UPDATE commando's, ik zal ze beide laten zien, maar probeer met een UPDATE zoveel mogelijk velden in een keer te wijzigen:
De update met 2 Commando's (zoveel mogelijk voorkomen):

update voorbeeldtabel set voornaam = 'aaaaa' where nummer = 5 ;
update voorbeeldtabel set e_mail = 'ccccc' where nummer = 5 ;

of met een update commando, (de beste manier):

update voorbeeldtabel set voornaam = 'aaaaa', e_mail = 'ccccc' where nummer = 5 ;

Als we het nu ook nog mooi uitschrijven krijgen we het volgende:

pguserid=> update voorbeeldtabel
pguserid-> set    voornaam = 'aaaaa', e_mail = 'ccccc'
pguserid-> where  nummer = 5 ;
UPDATE 1
pguserid=> select * from voorbeeldtabel;
 nummer |   voornaam   |           achternaam           |                       e_mail
--------+--------------+--------------------------------+----------------------------------------------------
      1 | uw voornaam  | uw achternaam                  | uw e-mail adres
      2 | Martie       | Krukkeland                     | martiekr@worldonline.nl
      3 | De Laatste   | Derde Achternaam               | En nog een E-mail adres
      4 | ababa        | bbbb                           | ddddd
      5 | aaaaa        | bbbb                           | ccccc
(5 rows)

pguserid=>

En zie, de voornaam en het e_mail adres van record 5 zijn geworden zoals wij dat hadden gevraagd.
Nu mag u zelf proberen de laatse twee records (4 + 5) te verwijderen. Het kan met 2 DELETE commando's maar ook met 1 DELETE commando (hint: achternaam is bij beide records het zelfde)..

Nu hebben we de basis vaardigheden van het Database(Tabel)Ontwerp en gebruik onder de knie. Probeer zelf ook eens Records toe te voegen, op te vragen, te wijzigen en weer te verwijderen, zodat u een gevoel krijgt hoe u met SQL uw informatie in een tabel kunt beheren. U dient altijd te eindigen met alleen de eerste 3 hierboven getoonde records, want het vervolg van dit voorbeeld is hierop gebasseerd.

Indien u er niet meer uit komt, kunt u met:

drop table voorbeeldtabel ;
drop sequence voorbeeldtabel_nummer_seq ;

uw 'rommel' op ruimen en weer van voren af aan beginnen (zie Eerste Commando's en Tabel Maken enz.)

HTML:

We gaan nu het zichtbare deel van ons voorbeeldsysteem maken, de HTML-Pagina die in de browser zal worden getoont na het intypen van ons web-adres.
(Een volledig voorbeeld van dit voorbeeldsysteen is hier te vinden: show.)

Deze eerste pagina heeft in de internet-wereld altijd de volgende naam: index. Als bestandsextentie kunnen we bv. kiezen uit "htm", "html", "php", "asp" enz.
De extentie bepaald hoe er met het betreffende bestand om moet worden gegaan. 'HTML' geeft aan dat het om een 'statische' pagina gaat, dwz. deze pagina zal er na 10 jaar nog steeds het zelfde uitzien. Wij gaan echter een 'dynamische' pagina maken, een pagina die er dus iederen keer als we hem bekijken anders kan zijn (er kunnen namelijk namen bij zijn gekomen, namen zijn veranderd of namen zijn verwijderd).
Ik kies hier voor de naam index.html. Bij het openen van de genoemde link zal dus het bestand: index.html worden geopend. Hier merkt u niets van, dit wordt door de webserver gedaan van de unix-machine waar deze pagina op staat. Verdop gaan ze deze van naam veranderen als we daadwerkelijk informatie uit onze database-tabel willen gaan halen omdat we dan de pagina 'dynamisch' gaan maken.

We beginnen met het maken van de totaal-lijst van onze tabel.
Deze pagina ziet er zo uit (zonder data er in):

Informatie in onze Voorbeeld database:

Voornaam Achternaam E-mail adres
     
 

Niet erg schokkend toch? De lege velden onder de kopregel gaan we later vullen met de namen vanuit onze voorbeeld-database-tabel.
Hoe hebben we deze pagina gemaakt?, hieronder staat code om deze pagina te kunnen maken (deze code staat dus in het 'index.html' bestand):

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
<HTML>
<HEAD>
  <META NAME="GENERATOR" CONTENT="Code-genie/Notepad">
  <TITLE>Hoe maak ik een dynamische Website.</TITLE>
</HEAD>
<BODY>
<H1>Informatie in onze Voorbeeld database:</H1>
<TABLE border='1'>
<TR>
<TH>Voornaam</TH><TH>Achternaam</TH><TH>E-mail adres</TH>
</TR>
<TR>
<TD>&nbsp;</TD><TD>&nbsp;</TD><TD>&nbsp;</TD>
</TR>
</TABLE>
</BODY>
</HTML>

Een html-pagina bestaat minimaal uit het volgende (zeg maar de basis) regels:

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
<HTML>
<HEAD>
  <TITLE>Hoe maak ik een dynamische Website.</TITLE>
</HEAD>
<BODY>
</BODY>
</HTML>

De rest voegen we zelf toe om daadwerkelik iets te kunnen zien. In HTML draait alles om de zgn. 'TAG's'. TAG's zijn de woordjes met de '<' en de '>' er voor en er na. Deze bepalen hoe de tekst moet worden getoont. Er zijn er een groot aantal van, op onze voorbeeld pagina ('index.html') staan er al 20 (tel ze hierboven maar).
Was het je al opgevallen dat een groot aantal hiervan in 'paren' voorkomen: (zoals: <TH> en </TH>)? Dit omdat tags bijna altijd een tekstblok omsluiten, je hebt dus een open-tag en een sluit-tag. De TAG's mogen worden geschreven in hoofdletters en in kleine letters, dit maakt niet uit, maar voor de leesbaarheid geef ik de voorkeur aan hoofdletters.
Bv. de volgende html-regel:

Dit is een html-regel met een <B>vette</B> 
en <I>schuine</I> tekst er in.

zal er zo uit komen te zien:

Dit is een html-regel met een vette en schuine tekst er in.

De TAG-paren: "<B>" en "</B>" zullen de tekst er tussen in vet (=Bold) afdrukken en
de TAG-paren: "<I>" en "</I>" zullen de tekst er tussen in schuin-schrift (=Italic) afdrukken.

Nu gaan we onze pagina 'index.html' hernoemen naar 'index.php' omdat we nu code gaan inbouwen om informatie uit een database-tabel te kunnen halen.
Dit omdat we de programmeertaal 'PHP' gaan gebruiken om contact te leggen met onze voorbeeld-database en daar informatie uit gaan halen. De programmeertaal 'PHP' staat gewoon als tekst in een HTMl-Pagina, en ogenschijnlijk is er geen verschil. Echter omdat 'PHP' geen 'HTML' is hebben we het (index.html) bestand een andere naam gegeven zodat we gelijk hennen zien dat we hier niet te maken hebben met een statische HTML pagina maar met een dynamische pagina. Ook heeft dit het voordeel dat de webserver direct weet dat het nu iets anders moet doen met de tekst die in deze pagina staat. Echter: bij een correct ingestelde webserver zal ook deze geen probleem hebben met de naam en ook een 'html' pagina met php code er in correct verwerken.

Omdat de html-code (zie hierboven) een ander doel heeft dan de code die we gaan toevoegen om de informatie uit een database-tabel te halen, ga ik deze in twee kleuren tonen. De HTML-code toon ik in ' donker-groen' en de PHP-Code toon ik in 'licht-paars'.

Als eerste gaan we een pagina maken die de verbinding met onze Database maakt. Hierin komt dus te staan: het user-id en het wachtwoord van onze database-account (pguserid met het daarbij behorende wachtwoord).
Deze pagina geven de bijvoorbeeld de naam: xxConnect.php.

de inhoud van deze pagina ziet er zo uit:

<?php
$pgConnection=pg_connect("host=localhost dbname=pguserid user=pguserid password=pgwachtwoord");
?>

Nu zult u denken, maar het wachtwoord staat leesbaar in het bestand, dat is toch niet veilig??. Maar probeert u maar eens dit bestand te openen in uw webbrowser, dan zult u zien dat het toch wel veilig is:
show/xxConnect.php

Het is gewoon een lege pagina, geen enkele informatie er in. Alleen al het feit dat u een lege pagina krijgt beteketn dat alle werkt zioals het zou moeten, zelfs de connect naar de database ging goed. probeert u maar een een foutief wachtwoord in het bestand te zetten en zie wat er dan gebeurt:

Warning: pg_connect() unable to connect to PostgreSQL server: FATAL 1: Password authentication failed for user "pguserid" in /var/www/html/martie/voorbeeld-systeem/show/xxConnect.php on line 2

Hieraan ziet u dat er wel degelijk iets is gebeurt bij het openen van dit bestand. Maar deze pagina hoort ook nooit op deze manier te worden geopent, dit alleen als test om te controleren of de database-connect werkt (en hij werkt dus).

Hoe ziet de webserver nu wat HTML-code is en wat PHP-code is? Wel: de truuk is: alles wat tussen de '<?php' en de '?>' tags staat wordt behandeld als PHP-code.
vandaar ook dat onze xxConnect.php pagina deze twee tags heeft, standaard wordt elke pagina gezien als een HTML-Pagina. Met deze twee TAG's geven we aan dat er ook een stuk PHP-Code verwerkt moet worden. Daarom zagen we ook niets bij het rechtstreeks openen, er staat geen HTML-tekst in, alleen PHP-Code en dit wordt nooit getoont.

Nu gaan we deze code opnemen in onze 'index.php' bestand en tegelijk alle records uit onze database ophalen (we tonen ze nog niet!!).
Met het PHP 'require' commando kunnen we een andere HTML-Pagina invoegen in deze pagina. Na de 'require' hebben we dus een connect met de database.

Het betreffende 'index.php' bestand ziet er dan zo uit.

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
<HTML>
<HEAD>
  <META NAME="GENERATOR" CONTENT="Code-genie/Notepad">
  <TITLE>Hoe maak ik een dynamische Website.</TITLE>
</HEAD>
<BODY>
<H1>Informatie in onze Voorbeeld database:</H1>
<TABLE border='1'>
<TR>
<TH>Voornaam</TH><TH>Achternaam</TH><TH>E-mail adres</TH>
</TR>
<?php
	require("xxConnect.php");
	
	$Query  = "select * from voorbeeldtabel;";
	$tabelinfo = pg_query($pgConnection, $Query ); 		
	for ($i = 0; $i < pg_num_rows($tabelinfo); $i++) 
		{
		$row = pg_fetch_object($tabelinfo, $i);
	}		
?>
<TR>
<TD>&nbsp;</TD><TD>&nbsp;</TD><TD>&nbsp;</TD>
</TR>
</TABLE>
</BODY>
</HTML>

Er is aan de werking nog steeds niets verandert, de browser stoont nog steeds ons vertrouwde beeld met de 3 lege velden. Maar (onzichtbaar) zijn alle records al opgehaalt. We hebben met een "Select * from voorbeeldtabel" werkelijk de alle records opgehaald (en ze in de 'for' lus 1 voor 1 bekeken). Met een 'for' lus kunnen we een bepaalde handeling (of handelingen) herhaaldelijk uitvoeren. De handelingen die wij hierboven hebben verricht is elk record (=pg_num_rows) 1 voor 1 'bekijken' (=pg_fetch_object), maar verder deden we nog niets. daar gaan we nu verandering in brengen, we geen de 'bekeken' records nu daadwerkelijk tonen.

Hiertoe passen we onze 'index.php' aan zodat het er nu zo uitziet:

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
<HTML>
<HEAD>
  <META NAME="GENERATOR" CONTENT="Code-genie/Notepad">
  <TITLE>Hoe maak ik een dynamische Website.</TITLE>
</HEAD>
<BODY>
<H1>Informatie in onze Voorbeeld database:</H1>
<TABLE border='1'>
<TR>
<TH>Voornaam</TH><TH>Achternaam</TH><TH>E-mail adres</TH>
</TR>
<?php
	require("xxConnect.php");
	
	$Query  = "select * from voorbeeldtabel;";
	$tabelinfo = pg_query($pgConnection, $Query ); 		
	for ($i = 0; $i < pg_num_rows($tabelinfo); $i++) 
		{
		$row = pg_fetch_object($tabelinfo, $i);
		echo "<TR>\n";
		echo "  <TD>$row->voornaam</TD>\n";
		echo "  <TD>$row->achternaam</TD>\n";
		echo "  <TD>$row->e_mail</TD>\n";
		echo "</TR>\n";
	}		
?>
</TABLE>
</BODY>
</HTML>

Zoals u waarschijnlijk heeft gezien hebben we de HTML-TAG's <TR>,<TD>,</TD> en </TR> verplaatst naar binnen de 'for' lus. Wat we hier dus doen is de veld-informatie van elk 'bekeken' (=in $row) record tonen (met 'echo') binnen een HTML-Tag (<TD> en </TD>). U merkt waarschijnlijk op dat PHP dus feitelijk HTML-Code afdrukt. En dat is ook zo, alles wat u met het PHP commando 'echo' afdrukt wordt in uw browser als HTML-Code getoont.