Avatar billede martin1000ben Nybegynder
03. maj 2006 - 14:39 Der 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 :)
Avatar billede kjulius Novice
03. maj 2006 - 20:31 #1
Hvad siger du til denne her?

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
Avatar billede martin1000ben Nybegynder
05. maj 2006 - 10:49 #2
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...)
Avatar billede kjulius Novice
05. maj 2006 - 19:52 #3
Du skriver:

"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?
Avatar billede kjulius Novice
05. maj 2006 - 19:55 #4
... og endnu engang var sættenissen på spil... :-(

Hvor der står "for du mangler jo at knytte tbl_itemprices til de andre på ID", skulle der naturligvis have stået tbl_campaign.
Avatar billede kjulius Novice
05. maj 2006 - 19:59 #5
... sættenissen har haft travlt...

Hvor der står "... ,for der mangler en alias ip på tabellen tbl_campaign", skulle der naturligvis have stået tbl_itemprices
Avatar billede martin1000ben Nybegynder
09. juli 2006 - 14:49 #6
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.
Avatar billede martin1000ben Nybegynder
25. juli 2006 - 09:03 #7
lukker
Avatar billede Ny bruger Nybegynder

Din løsning...

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.

Loading billede Opret Preview
Kategori
Computerworld tilbyder specialiserede kurser i database-management

Log ind eller opret profil

Hov!

For at kunne deltage på Computerworld Eksperten skal du være logget ind.

Det er heldigvis nemt at oprette en bruger: Det tager to minutter og du kan vælge at bruge enten e-mail, Facebook eller Google som login.

Du kan også logge ind via nedenstående tjenester