03. maj 2006 - 14:39Der er
6 kommentarer og 1 løsning
Select over 3 tabeller
Jeg har et lille problem med at finde en løsning på mit statement.
Beskrivelse af mine 3 tabeller.
tbl_item = varer produkter ID navn normal_pris
tbl_campaign = kampagner ID navn from_date (datetime) to_date (datetime)
tbl_campaignitems = varer til kampagne ID item_ID campaign_ID kampagne_pris
Mit ønske er: at få varens navn og ID at få de x antal varer ud med størst forskel mellem normal_pris og kampagne_pris (denne er ikke et krav, da jeg kan lave det med PHP, hvis det skulle være) og til sidst, at kun få varer ud der ER en kampagne på :)
Det hele kører på MySQL 4.0.24, sammen med PHP 5 :)
Denne side indeholder artikler med forskellige perspektiver på Identity & Access Management i private og offentlige organisationer. Artiklerne behandler aktuelle IAM-emner og leveres af producenter, rådgivere og implementeringspartnere.
SELECT i.ID, i.navn, i.normal_pris, ki.kampagne_pris, i.normal_pris - ki.kampagne_pris as prisforskel FROM tbl_campaignitems ki INNER JOIN tbl_item i ON ki.item_ID = i.ID INNER JOIN tbl_campaign k ON ki.ID = ki_campaign_ID WHERE NOW BETWEEN k.from_date AND k.to_date ORDER BY ABS(i.normal_pris - ki.kampagne_pris) DESC LIMIT 10
SELECT it.ID, it.Navn, (ip.normal_pris - ci.kampagne_pris) AS Forskel FROM tbl_item it, tbl_campaignitems ci, tbl_campaign tc, tbl_itemprices WHERE ip._item_id = it.ID AND it.ID = ci.item_ID AND (CURDATE() BETWEEN tc.from_date AND tc.to_date) ORDER BY Forskel DESC LIMIT 0,xx
Denne virker...
Jeg er stødt ind i et problem.
Problemet er nu, at jeg har fundet ud af at priserne ligger i en 4. tabel.
Altså: tbl_prices = priser på varerne ID item_ID date_add (datetime) price
Mit ønske er stadig det samme som før. Men nu ligger priserne jo i en 4. tabel.
Jeg har selvfølgelig prøvet at skrive:
SELECT it.ID, it.Navn, (price.normal_pris - ci.kampagne_pris) AS Forskel FROM tbl_item it, tbl_campaignitems ci, tbl_campaign tc, tbl_prices price WHERE price.item_ID = (1) it.ID = ci.item_ID AND (CURDATE() BETWEEN tc.from_date AND tc.to_date) ORDER BY Forskel DESC LIMIT 0,10
(1) = Her er prøvet en MASSE, men intet har virket endnu. Ligefra it.ID og til en inner select(?) altså (SELECT price FROM...)
"SELECT it.ID, it.Navn, (ip.normal_pris - ci.kampagne_pris) AS Forskel FROM tbl_item it, tbl_campaignitems ci, tbl_campaign tc, tbl_itemprices WHERE ip._item_id = it.ID AND it.ID = ci.item_ID AND (CURDATE() BETWEEN tc.from_date AND tc.to_date) ORDER BY Forskel DESC LIMIT 0,xx
Denne virker..."
Det er muligt den virker, men den virker garanteret ikke rigtigt (og jeg tror heller ikke engang på det, for der mangler en alias ip på tabellen tbl_campaign), for du mangler jo at knytte tbl_itemprices til de andre på ID. Den forespørgsel du skriver burde give alt for mange rækker. For hver række i tbl_item vil den returnere lige så mange rækker som der er i tabel tbl_campaign i det angivne tidsrum. Eller måske har du bare været heldig, og der var kun én kampagne, der kørte i den tidsperiode du har valgt. Men det er vist lidt meget at håbe på, at det altid vil være tilfældet.. :-) Da du ikke angiver inner joins, men bare angiver tabellerne separeret med komma (altså et såkaldt kartesian product), som du så afgrænser i din WHERE sætning, får du ingen fejlmelding. Det er bl.a. grunden til, at jeg til enhver tid vil foretrække direkte at specificere sammenhængen som en INNER JOIN. Det gør det lettere at overskue sammenhængen og nogle databaser vil også være bedre til at optimere et sådant udtryk.
Men i hvert fald burde du tilføje et ekstra kriterie:
SELECT it.ID, it.Navn, (ip.normal_pris - ci.kampagne_pris) AS Forskel FROM tbl_item it, tbl_campaignitems ci, tbl_campaign tc, tbl_itemprices ip WHERE ip._item_id = it.ID AND it.ID = ci.item_ID AND tc.ID = ci.campaign_ID AND (CURDATE() BETWEEN tc.from_date AND tc.to_date) ORDER BY Forskel DESC LIMIT 0,xx
Som sagt foretrækker jeg personligt formen
SELECT it.ID, it.Navn, (ip.normal_pris - ci.kampagne_pris) AS Forskel FROM tbl_item it INNER JOIN tbl_itemprices ip ON ip._item_id = it.ID INNER JOIN tbl_campaignitems ci ON it.ID = ci.item_ID INNER JOIN tbl_campaign tc ON tc.ID = ci.campaign_ID WHERE (CURDATE() BETWEEN tc.from_date AND tc.to_date) ORDER BY Forskel DESC LIMIT 0,xx
Hvis du på denne form havde udeladt betingelsen ON tc.ID = ci.campaign_ID, ville du have fået en fejl. Jeg håber du kan se fordelen ved at angive en INNER JOIN?
Hov, jeg havde helt glemt denne - Undskyld. Men efter et helt nyt database design og en masse ekstra features så har der været mange mange ændringer, så nu er det hele lavet i en klasse i PHP.
Men hvis du smider et svar kjulius, så får du nogle point.
Tilladte BB-code-tags: [b]fed[/b] [i]kursiv[/i] [u]understreget[/u] Web- og emailadresser omdannes automatisk til links. Der sættes "nofollow" på alle links.