Door verkoopgegevens goed op te slaan en later te combineren, kan een voorspellend model met een hoge nauwkeurigheid worden gecreëerd. In dit en de volgende artikelen analyseren we een databaseontwerp voor het registreren van verkopen.
Iedereen leeft door iets te verkopen.
Robert Louis Stevenson
In de wereld van vandaag producten verkopen is alomtegenwoordig. En verkopers die toegang hebben tot robuuste tools die historische gegevens gebruiken om trends te analyseren en een onderneming in staat te stellen bedrijfsstrategieën dienovereenkomstig aan te passen, hebben een voordeel ten opzichte van hun concurrenten. Er zijn veel parameters die van invloed kunnen zijn op de bedrijfsresultaten:de huidige wereldwijde economische situatie, de locatie van de klant, de leeftijd, materiële en burgerlijke staat en de geschiedenis van eerdere contacten of verkopen aan klanten.
We beginnen met een heel eenvoudig voorbeeld:een databasemodel voor verkoop in een koffiebar . In volgende artikelen breiden we het model uit naar de verkoop van producten in andere branches.
Verkoopmodel
In dit artikel analyseren we slechts een deel van het model dat verkoopgegevens bevat, terwijl andere onderdelen ontbreken.
We hebben nog steeds verbindingen met ontbrekende tabellen en we zullen het model als een black-box beschouwen, ervan uitgaande dat het volgende correct is voor tabel sale
:
user_has_role_id
verwijs naar id inuser_has_role
(zoals gepresenteerd in mijn vorige artikel in de sectie "Tijdcomponent toegevoegd") en slaat informatie op over de gebruiker die een verkooprecord heeft gemaakt
Dit model stelt ons in staat om verkooprecords aan te maken met meerdere artikelen. Elk item is gerelateerd aan een product uit onze catalogus. Het moment waarop we een verkoop genereren kan verschillen van het moment waarop de verkoop wordt betaald. Voor een kopje koffie bijvoorbeeld verschillen deze momenten in een kwestie van minuten of uren. Als onze winkel telecommunicatieapparatuur verkocht, kan het verschil een paar dagen, misschien zelfs maanden zijn.
Tafels
Laten we eens kijken naar de tabeldefinitie en het doel en het gebruik van attributen uitleggen.
De belangrijkste tabel in het model is product
. Het wordt gebruikt om details op te slaan over producten die we aan onze klanten aanbieden. Producten worden meestal bij een klant afgeleverd en eenmalig betaald, meestal op het moment van bezorging. Bovendien zijn producten meestal fysieke objecten zoals auto's, telefoons, pakjes suiker of kopjes koffie.
We zullen het hebben over het verkopen van niet-fysieke dingen (diensten) in de volgende artikelen.
Kenmerken in het product
tafel zijn:
name
– de naam van het product in het systeemprice_per_unit
– productkosten per eenheid (bijv. 1 kopje koffie kost 1,8 euro, 1 auto kost 17.500 euro, 1 kg rijst kost 2 euro)basic_unit
– basiseenheid wanneer we een product verkopen (bijv. stuk, kg, liter)tax_percentage
– percentage van de prijs_per_eenheid dat als belasting in rekening wordt gebracht. We moeten ervan uitgaan dat het belastingpercentage niet voor alle producten hetzelfde zal zijnlimited
– dit veld is ingesteld op True als we een beperkte hoeveelheid op voorraad hebben en anders False (we kunnen bijvoorbeeld elke gewenste hoeveelheid voor onze winkel bestellen bij een distributeur)in_stock
– if limited=True, dit kenmerk laat zien hoeveel we beschikbaar hebben om te verkopenactive_for_sale
- als dit kenmerk False is, bieden we dat product momenteel niet te koop aan, anders kunnen we het aan klanten aanbieden
We kunnen een lijst krijgen van producten die we aan klanten kunnen aanbieden met de volgende vraag:
SELECT product.id, product.price_per_unit, product.basic_unit, product.limited, product.in_stock FROM product WHERE product.active_for_sale = True AND (product.limited = False OR (product.limited = True and product.in_stock > 0))
De tabel sale_status
is slechts een eenvoudig woordenboek dat alle statussen bevat die een verkoop in het systeem kan hebben (bijv. "ontvangstbewijs", "ontvangstbewijs betaald").
De tafel
sale
is de tweede belangrijkste tafel in dit model. Tot nu toe heeft deze tabel geen verband met klanten aan wie we producten hebben verkocht, omdat we dergelijke informatie in ons coffeeshopvoorbeeld niet hoeven te weten. In deel 2 wordt het model uitgebreid om dergelijke gevallen te dekken. Attributen in de tabel en hun betekenis zijn:
time_created
– tijd waarop een verkooprecord werd gegenereerd in het systeem (bijv. automatische tijd dat het record werd gemaakt toen we een verkoop voor koffie in onze coffeeshop genereerden of een handmatig toegevoegde tijd als we dat willen)time_paid
– over het algemeen kunnen we verwachten dat sommige verkopen binnen een paar dagen of zelfs een maand na creatie worden betaald (als we bijvoorbeeld software leveren en een ontvangstbewijs maken, kunnen we in sommige landen tot 90 dagen wachten om betaald te worden, als alles doorgaat de wet)sale_amount
– oorspronkelijk bedrag bedoeld om aan de klant in rekening te worden gebrachtsale_amount_paid
– bedrag dat de opdrachtgever daadwerkelijk heeft betaald. Het kan nul zijn, want op het moment dat we een ontvangstbewijs maken, hebben we deze informatie niet altijdtax_amount
– som van alle belastingbedragen voor items op die bonsale_status_id
– verwijzing naarsale_status
tafeluser_has_role_id
– verwijzing naar de gebruiker en zijn rol op het moment dat hij of zij de bon in het systeem invoerde
We kunnen het uitgegeven en betaalde bedrag (volgens time_created) binnen een bepaalde periode krijgen met een zoekopdracht als volgt:
SELECT SUM(sale.sale_amount) AS amount_issued, SUM(sale.sale_amount_paid) AS amount_paid FROM sale WHERE sale.time_created >= @start_time AND sale.time_created <= @end_time;
Om het exacte bedrag binnen een bepaalde tijd betaald te krijgen, moeten we een zoekopdracht als deze gebruiken:
SELECT SUM(sale.sale_amount_paid) AS amount_paid FROM sale WHERE sale.time_paid >= @start_time AND sale.time_paid <= @end_time;
De onderstaande zoekopdracht berekent het uitgegeven en betaalde bedrag binnen een bepaalde periode waarbij de uitgiftedatum en betalingsdatum afzonderlijk worden gecontroleerd:
SELECT SUM(CASE WHEN sale.time_created >= @start_time AND sale.time_created <= @end_time THEN sale.sale_amount END) AS amount_issued, SUM(CASE WHEN sale.time_paid >= @start_time AND sale.time_paid <= @end_time THEN sale.sale_amount_paid END) AS amount_paid FROM sale
In alle voorbeelden @start_time
en @end_time
zijn variabelen die de begintijd en eindtijd bevatten van de periode waarvoor we de uitgegeven en betaalde SOM willen controleren.
De tabel sale_item
verbindt producten en verkoop. We moeten er natuurlijk van uitgaan dat we meerdere items hebben op één bon, dus we hebben deze tabel nodig om een veel-op-veel-relatie te hebben.
Attributen en hun betekenis zijn:
quantity_sold
– hoeveelheid product die is verkocht en die op die verkoop/ontvangst wordt afgerekend (bijv. 3 koffies)price_per_unit
– dezelfde waarde alsproduct.price_per_unit
op het moment waarop de koop tot stand is gekomen. We moeten het opslaan omdatprice_per_unit
in hetproduct
tabel kan in de loop van de tijd veranderenprice
– product vanquantity_sold
enprice_per_unit
; een kleine redundantie die ons helpt om deze berekening in query's te vermijden. Over het algemeen moet de som van alle artikelprijzen die bij dezelfde verkoop horen gelijk zijn aan desale.sale_amount
tax_amount
– belastingbedrag voor dat artikel bij ontvangstsale_id
– ID van de verkoop waartoe dit item behoortproduct_id
– product-ID gerelateerd aan dit artikel
We konden nu eenvoudig een eenvoudig rapport maken, hoeveel producten/diensten we in een periode hebben verkocht en tegen welke prijs.
SELECT product.name, SUM(sale_item.quantity_sold) AS quantity, SUM(sale_item.price) AS price FROM sale, sale_item, product WHERE sale.id = sale_item.sale_id AND sale_item.product_id = product.id AND sale.time_created >= @start_time AND sale.time_created <= @end_time GROUP BY product.id