Lastige query over drie tabellen
Noppes:
Wat bedoel je daarmee?En joinen in de select niet echt aan te bevelen....
Dat als je subqueries maakt in het select gedeelte dat je die onafhankelijk moet maken.
Als ik een overzicht wil hebben van alle orders, dan is het toch logisch dat ik groepeer op orders.id?
http://efloria.nl/orders_overzicht.gif
Misschien verduidelijkt het de boel een beetje, maar volgens mij begrijpen jullie me al erg goed. Als de query die ik gebruik niet goed is, wat zou dan wel een goede query zijn om deze data terug te krijgen?
Gelieve Niet Bumpen::
Gewijzigd op 01/01/1970 01:00:00 door Roberto Beer
Nee, dat is niet logisch. In je hoofdquery staat namelijk nergens een aggregate functie die een GROUP BY vereist.
Ik kwam erachter dat de subqueries binnen mijn query niet nodig zijn.
Code (php)
1
2
3
4
5
6
7
8
9
10
11
2
3
4
5
6
7
8
9
10
11
SELECT orders.id, date_format(orders.datum, '%d-%m-%Y - %H:%i') AS geplaatst, orders.status, CONCAT(klanten.achternaam, ', ', klanten.voornaam) as naam, SUM(orderregels.aantal * orderregels.prijs) AS order_totaal, SUM(orderregels.aantal) AS aantal_totaal
FROM orders, klanten, orderregels, producten
WHERE orderregels.orders_id = orders.id
AND orderregels.producten_id = producten.id
AND orders.klanten_id = klanten.id
GROUP BY orders.id
ORDER BY orders.id DESC;
FROM orders, klanten, orderregels, producten
WHERE orderregels.orders_id = orders.id
AND orderregels.producten_id = producten.id
AND orders.klanten_id = klanten.id
GROUP BY orders.id
ORDER BY orders.id DESC;
Doet precies hetzelfde. Is ie nu dan misschien goed?
----------- update:
Ik heb me na jullie kritiek eens verder verdiept in de Inner Join, de GROUP BY methode en waarom je aggregate functies moet gebruiken.
Als ik het samen mag vatten is dit de kwestie:
Je kunt alles zonder problemen uit de tabel orders halen, omdat je daarop groepeert. Maar het probleem is hoe die dan met de gegevens uit de andere tabellen moet omgaan, omdat deze min of meer 'in elkaar zijn geperst'. Dat is wat ik nu begrijp :)
Ik zie in het SELECT-gedeelte van mijn query...
Code (php)
1
2
3
4
2
3
4
SELECT orders.id, date_format(orders.datum, '%d-%m-%Y - %H:%i') AS geplaatst,
orders.status, CONCAT(klanten.achternaam, ', ', klanten.voornaam) as naam,
SUM(orderregels.aantal * orderregels.prijs) AS order_totaal,
SUM(orderregels.aantal) AS aantal_totaal
orders.status, CONCAT(klanten.achternaam, ', ', klanten.voornaam) as naam,
SUM(orderregels.aantal * orderregels.prijs) AS order_totaal,
SUM(orderregels.aantal) AS aantal_totaal
... dat ik dat met de velden die ik ophaal uit ORDERREGELS ook doe :) Geen probleem daar, lijkt me. Wat ik denk waar de verwarring in zit is dat ik niet heb uitgelegd dat in mijn gebouwde systeem een klant niet meer dan 1 order kan hebben.
Dit komt omdat gebruikers zich niet kunnen registeren. "Waarom laat je die tabel KLANTEN dan niet gewoon weg en zet je naam, adres, postcode et cetera niet in ORDERS?", hoor ik jullie vragen.
Welnu, ik heb dit gedaan met het oog op de toekomst. Mocht ik ooit nog een account-functie willen maken voor de gebruikers, dan is de tabellen-structuur in ieder geval goed (Ik weet ook dat, mocht ik zo'n functie gaan maken, dat de query alsnog aangepast moet worden).
Maar voor nu is de relatie KLANTEN - ORDERS 1 op 1. Dan hoeft er op de data uit de tabel KLANTEN toch geen aggregate functie worden toegepast? (omdat de data uit KLANTEN niet 'in elkaar' wordt 'geperst')
Ik ben benieuwd naar jullie reactie. Ik heb in ieder geval het gevoel dat ik het begin te begrijpen ;)
Gewijzigd op 01/01/1970 01:00:00 door Roberto Beer
http://www.w3schools.com/sql/sql_groupby.asp
En gaat op internet opzoek naar hoe je op correcte wijze met sub queries moet omgaan.
Het juiste gebruik van GROUP BY
En de query die je kunt gebruiken om MySQL in een strictere mode te zetten vind je hier.
Wat ik niet helemaal snap, want als ik op ID groepeer, wat een unieke waarde heeft, waarom zou je dan nog op andere velden moeten groeperen?
Maarja, als ik dat toepas, is 'ie dan foutloos ;)?
Je schrijft heldere tutorials trouwens. Petje af.
Roberto schreef op 14.06.2009 15:08:
De kolom orders.id zal in de orders tabel best uniek zijn en als je alleen velden uit die tabel selecteert zal er inderdaad niet veel aan de uitkomst veranderen. Maar dat neemt niet weg dat je niet op die kolommen moet groeperen, dat is namelijk de standaard en je voorkomt ermee dat er later bugs in je query sluipen.Wat ik niet helemaal snap, want als ik op ID groepeer, wat een unieke waarde heeft, waarom zou je dan nog op andere velden moeten groeperen?
Een ander verhaal is het als je ook kolommen uit andere tabellen selecteert. Dan hoeft orders.id niet per se meer unieke records op te leveren aangezien er bijvoorbeeld meerdere orderregels per order zijn.
Kortom, onthoud de vuistregel dat je altijd groepeert op alle kolommen in de SELECT waarop geen aggregatie is toegepast. Dan zit je altijd goed. (Andere databases dan MySQL dwingen dit trouwens standaard af).
Wat is de beste manier om klanten.naam erbij op te halen? Een order heeft altijd een klant.
Ik heb nu:
Code (php)
1
2
3
4
2
3
4
SELECT orders.id, date_format(orders.datum, '%d-%m-%Y - %H:%i') AS geplaatst,
orders.status, CONCAT(klanten.achternaam, ', ', klanten.voornaam) as naam,
SUM(orderregels.aantal * orderregels.prijs) AS order_totaal,
SUM(orderregels.aantal) AS aantal_totaal
orders.status, CONCAT(klanten.achternaam, ', ', klanten.voornaam) as naam,
SUM(orderregels.aantal * orderregels.prijs) AS order_totaal,
SUM(orderregels.aantal) AS aantal_totaal
Waarin ik aggregatie toepas op velden uit ORDERREGELS. Alleen naam haal ik 'kaal' op, daar groepeer ik dan ook mede op.
Ik ben benieuwd hoe MySQL die tabel dan ophaalt.
Stel een order bestaat 3 orderregels, en ik zou niet groeperen.
Dan krijg ik bijvoorbeeld 3 rijen:
order_id klant_naam product id aantal
1 robbert 2 10
1 robbert 5 8
1 robbert 6 3
Dan zou ik denk ik iets als dit krijgen.
Hoe moet ik omgaan met klant_naam, het is namelijk een veld die niet uit ORDERS komt, maar uit KLANTEN. Moet ik deze aggregeren? Want er zal elke keer hetzelfde uitkomen.
Groeperen doe je alleen als je eigenschappen van een groep wilt bepalen. Dus bijvoorbeeld aantal records in een groep, totalen van een bepaalde groep, etc.
Daarom was mijn vraag hoe de query omgaat met klanten.naam, omdat ik daar verder geen aggregatie op toepas.
In sommige queries (en je huidige query ook) zal het geen invloed hebben op de uitkomst aangezien je ook groepeert op een gegeven dat andere groepen verder onder verdeelt (orders.id verdeelt klanten.naam verder). De groepen die gemaakt worden door het groeperen op order.id worden dus aangehouden. Maar voor een correcte query is het van belang dat je wel blijft groeperen op alle kolommen, dus ook op klanten.naam.