Datumreeks

30 maart 2000

Soms heb je een reeks getallen nodig. Soms wil je alle datums weten tussen twee gegeven datums in, bijvoorbeeld; omdat datums nu eenmaal als getallen worden opgeslagen, kun je dat doen door een reeks getallen tussen de twee datums in te leggen.

Stel je voor: in een hotel reserveert een gast een kamer van een begindatum tot een einddatum. De manager (niet de ontwerper natuurlijk) van degene die het administratieprogramma gebruikt, heeft behoefte aan een overzicht per dag, welke gasten een kamer gereserveerd hebben.
Probleem: je hèbt niet al die dagen in je database. En je gaat ze er zeker niet in zetten... wat een onzin. Maar wat dan wel?

Laten we dit eens van boven af aanpakken. Ik wil straks een rapport zien per dag. Dat wil zeggen dat er nu een query moet komen, die voor elke dag minstens een record tevoorschijn haalt. Deze query wordt de gegevensbron voor het rapport (ik kom daar verder niet op terug - maak er iets moois van).

De query moet alle dagen laten zien, in een bepaald bereik, en voor iedere dag de gereserveerde kamers. Dat wijst op een fraaie datastruktuur. We nemen een tabel met kamers, en een tabel met reserveringen:
tblKamer
veldnaamgegevenstype
kamerIDAutonummer
kamernummerLange integer
tblReservering
veldnaamgegevenstype
resIDAutonummer
datBeginDatum
datEindDatum
kamerIDLange integer

De query moet uit twee stukken bestaan, eentje die alle dagen maakt in het gevraagde bereik, en eentje die van alle kamers alle dagen produceert.

Eerste queryhelft

Nu komen we in de buurt. Het eerste querydeel is eigenlijk het makkelijkste: alle dagen in het gevraagde bereik. We zullen ervan uitgaan dat er een tabel is, met twee datumvelden, die het gewenste bereik weergeeft. Deze tabel noem ik tblBereik:
tblBereik
veldnaamgegevenstype
datumVanDatum
datumTotDatum

Om nu alle datums in het bereik weer te geven, maak ik een reeks getallen van 0 tot veel, die ik steeds bij de begindatum optel tot ik voorbij de einddatum ben.

Hoe maak je een reeks getallen?

Ik begin met een basistabel met één veld, en tien records.
tblBase
veldnaamgegevenstype
nummerLange integer

De records zijn: 0, 1, 2, 3, 4, 5, 6, 7, 8, 9

Wat betekent 325? 3x100 + 2x10 + 5(x1). Zo zit ons nummerstelsel in elkaar. Om alle getallen van 0 tot 100 te krijgen, neem ik het cartesisch produkt van tblBase met zichzelf. De SQL-opdracht ziet er zo uit:

SELECT tens.nummer*10 + ones.nummer AS theNumber
FROM tblBase AS tens, tblBase AS ones;

Is dat echt alles? Probeer maar! Voor iedere macht van 10 die je verder wilt, neem je een extra instantie van tblBase in de query op. Ik doe nog voor van 0 tot 1000:

SELECT hundreds.nummer*100 + tens.nummer*10 + ones.nummer AS theNumber
FROM tblBase AS hundreds, tblBase AS tens, tblBase AS ones;

Deze query sla ik op als qryThousand

Terug naar het datumbereik. Alle datums uit tblBereik krijg ik nu op deze manier:

SELECT datumVan+theNumber AS deDagInHetBereik
FROM qryThousand, tblBereik
WHERE (datumVan+theNumber)<= datumTot;

Deze query sla ik op als qryDateRange

De tweede queryhelft

Ik wil de combinatie van datum en kamernummer in het resultaat zien, wanneer de datum binnen de reservering valt. We combineren dus qryDateRange met tblReservering. Even verbinden met tblKamer om het kamernummer op te halen.

SELECT deDagInHetBereik, roomNumber
FROM qryDateRange, tblReservering INNER JOIN tblKamer ON tblReservering.kamerID = tblKamer.kamerID
WHERE deDagInHetBereik BETWEEN datBegin AND datEind;

Hier zit wel een maar aan. Als er op een bepaalde dag helemaal geen reserveringen zijn, verschijnt die dag niet in het rapport. Overtuig je manager... anders moet je een right join maken met alle datums. Kan dat eenvoudiger? Dat is je huiswerk.