FAQ |
Kalender |
![]() |
#1 | |||
|
||||
Flitig postare
|
Skulle behöva lite experthjälp gällande en mysql-query.
Det är flera tabeller som ska samköras, och hämta ut "rätt" sorts data från de olika tabellerna från en annonssida, och varje annonstyp är uppdelad i varsin databastabell, beroende på vilken typ av data tabellen innehåller. Tabell "AdvertiseList" innehåller en lista med övergripande data om vad de andra 3 tabellerna innehåller, såsom Datum, Id, MenuId osv. Förfrågningen såsom den ser ut idag: SELECT * FROM AdvertiseList, Advertise8, Advertise9, Advertise11 WHERE ((AdvertiseList.Id <> 0) AND ((AdvertiseList.MenuId = '8') OR (AdvertiseList.MenuId = '9') OR (AdvertiseList.MenuId = '11')) AND ((AdvertiseList.AdvertiseId = Advertise8.Id) OR (AdvertiseList.AdvertiseId = Advertise9.Id) OR (AdvertiseList.AdvertiseId = Advertise11.Id))) GROUP BY AdvertiseList.Id ORDER BY AdvertiseList.Date DESC - Alla de andra 3 tabellerna, dvs. "Advertise8", "Advertise9" och "Advertise11" innehåller tex. fältet "Header" och "Price" för namnet på annonser respektive priset, men vid förfrågningen ovan verkar den blanda samman vilken Header resp. Price som den ska visa, ibland tar den Header från Advertise8, ibland från Advertise9 osv... Vad ska jag göra? Borde väl vara någon JOIN, men är tyvärr inte så haj på SQL, så all hjälp uppskattas. Det hade fungerat om även Header och Price legat i "AdvertiseList" tabellen, då hade man bara gjort förfrågningen mot just den tabellen, men systemet rullar redan idag, och det innebär en hel del strul att ändra om databasstrukturen idag. ![]() |
|||
![]() |
![]() |
![]() |
#2 | ||
|
|||
Supermoderator
|
Du kan skapa alias för tabellerna såhär:
SELECT * FROM tabell1 AS t1, tabell2 AS t2 Kan kanske även vara bättre om du anger de fält (samt i vilken ordning) som ska hämtas ut. Så istället för * skriver du tex: SELECT id, col1, col2 FROM ... eller med alias som ovan: SELECT t1.id, t1.col1, t2.col1, t2.col2 FROM ... Då kommer du alltid få samma ordning på datan som hämtas ut. Sen kan du även (för att korta ner frågan lite) ersätta: AND ((AdvertiseList.MenuId = '8') OR (AdvertiseList.MenuId = '9') OR (AdvertiseList.MenuId = '11')) med detta: AND (AdvertiseList.MenuId IN (8,9,11)) |
||
![]() |
![]() |
![]() |
#3 | ||
|
|||
Mycket flitig postare
|
Ja ditt huvudproblem är ju att du inte har koll på vad du joinar ihop. Och bortsett från de andra generella tipsen du fått så vill du inte ha några "OR" om det går att undvika...
Till att börja med behöver du rätt data: Kod:
SELECT AL.Date, AL. MenuID, A.Header, A.Prize FROM AdvertiseList AL, Advertise8 A WHERE AdvertiseList.Id <> 0 AND AdvertiseList.MenuId = '8' AND AL.AdvertiseId = A.Id UNION SELECT AL.Date, AL. MenuID, A.Header, A.Prize FROM AdvertiseList AL, Advertise9 A WHERE AdvertiseList.Id <> 0 AND AdvertiseList.MenuId = '9' AND AL.AdvertiseId = A.Id UNION SELECT AL.Date, AL. MenuID, A.Header, A.Prize FROM AdvertiseList AL, Advertise11 A WHERE AdvertiseList.Id <> 0 AND AdvertiseList.MenuId = '11' AND AL.AdvertiseId = A.Id Outer joins borde fixa det också: Kod:
SELECT * FROM AdvertiseList AL LEFT OUTER JOIN Advertise8 A8 ON AL.AdvertiseID = A8.ID LEFT OUTER JOIN Advertise9 A9 ON AL.AdvertiseID = A9.ID LEFT OUTER JOIN Advertise11 A11 ON AL.AdvertiseID = A11.ID WHERE AL. MenuId in (8,9,11) Order by AL.Date |
||
![]() |
![]() |
![]() |
#4 | ||
|
|||
Supermoderator
|
Citat:
Starweb: Funkar frågan som den ser ut idag? Om enda problemet är att den blandar ihop fälten behöver du ingen join utan kan bara namnge fälten som jag visade. Sen använder du mysql_fetch_array() (den är något snabbare än mysql_fetch_assoc()) för att hämta ut datan på respektive position. Då får du alltid rätt data. |
||
![]() |
![]() |
![]() |
#5 | |||
|
||||
Flitig postare
|
Både sätten fungerar. Alltså dels döpa om fälten enligt ditt sätt Anders, samt att göra på eg0master's sätt:
Kod:
SELECT * FROM AdvertiseList AL LEFT OUTER JOIN Advertise8 A8 ON AL.AdvertiseID = A8.ID LEFT OUTER JOIN Advertise9 A9 ON AL.AdvertiseID = A9.ID LEFT OUTER JOIN Advertise11 A11 ON AL.AdvertiseID = A11.ID WHERE AL. MenuId in (8,9,11) Order by AL.Date - Tackar för all hjälp, har fått lite bättre insikt nu. Dock har DB-designen fungerat utmärkt på det den gjort tidigare, och anledningen till att tabellerna delades i flera "undertabeller" var pga. att detta ska bidra till mindre "tryck" på databasen då den endast hämtar lite data ur "huvudtabellen" och sedan resten ur rätt "undertabell"... Jag tycker detta borde vara mycket smartare än att ha allt i en stor tabell, speciellt då de olika tabellerna har flera andra olika fält på varje undertabell - förutom Header och Price. En annan fråga som har med ämnet att göra: Hur hade ni valt att struktura databastabellerna för bästa möjliga struktur, om ni utgår ifrån min förfrågning samt att det är en annonssida med flera olika typer av annonser? Om man lagt allt i en och samma tabell så hade man fått en oerhört bred tabell med en uppsjö av poster, vilket borde vara segare att ladda än ett flertal små som man länkar samman... Eller? Rätta mig gärna, och kom gärna med andra förslag. Är alltid bra inför framtida projekt. |
|||
![]() |
![]() |
![]() |
#6 | ||
|
|||
Supermoderator
|
Citat:
|
||
![]() |
![]() |
![]() |
#7 | ||
|
|||
Mycket flitig postare
|
Ang OR, OUTER JOIN och UNION:
Alla dessa konstruktioner suger. OR är alltid dåligt. Sannolikheten för en tablescan är nära 1. Har faktiskt aldrig testat just det med en outer join (eller "IN" heller för den delen), men även OUTER JOINs är elaka och bör undvikas. Problemet med UNION är lite mindre dels då den kommer gå igenom inte hela tabellen utan bara det temporära resultatet och även denna overhead kan minimeras med "UNION ALL" om man vet att inga dubletter finns (vilket ju är fallet här, så UNION ALL borde det vara). vad som är mest segt OR eller OUTER JOIN är i sammanhanget egentligen ointressant då resultatet inte är det samma. Det är två helt skilda konstruktioner med olika syften. Den intressanta jämförelsen är "OR vs IN" Ang hur du borde designat: Objektorientering är nyckelordet tror jag. Du ska ha en bastabell (AdvertiseList) med ALLA gemensamma fält. Header och Price är ju gemensamma fält och borde inte funnits i resp. undertabeller. Sedan kan du skapa utökningar av din bastabell med det specialiserade datat. Då "borde" du ha ett läge där du i varje given fråga inte behöver blanda in mer än bastabellen och en "barntabell". Om du ändå måste det så slutar det med flera frågor eller hemska outer joins. I alla fall om man ska vara flexibel. Om antalet "extra" kolumner är relativt få (till antal och datatyp) så skulel jag nog fundera på att ha allt i samma tabell och ha generella kolumner för extra datat givet att jag vill välja ut extradata från flera olika typer av "barn" |
||
![]() |
![]() |
![]() |
#8 | |||
|
||||
Flitig postare
|
Citat:
Men ditt förslag hade varit att istället för som nu har jag 1 BAS, och 10 BARN, så skulle du valt att ha 1 BAS, och 1 BARN ? Eller bara 1 BAS? Jo, jag tänkte först bara ha 1 BAS, men ändrade det sedan till multipla barntabeller för att inte den tabellen skulle dels bli "för bred", och dels bli "överanvänd"... - Diskutera gärna vidare, detta är både intressant och lärorikt! |
|||
![]() |
![]() |
![]() |
#9 | ||
|
|||
Supermoderator
|
Citat:
Bas innehåller all gemensam info. Specifik info för barnet ska bara finnas i tabellen för barnet. |
||
![]() |
![]() |
![]() |
#10 | ||
|
|||
Mycket flitig postare
|
För att citera mig själv... Objektorientering är nyckelordet...
jag var inte riktigt med på ditt upplägg. Men samma sak gälelr i flera nivåer i så fall... Om 3 "barn" har gemensamt data så lägg det i en gemensam tabell... Men även förslaget att "optimera för det vanligaste" gäller... Sånt här blir sällan riktigt snyggt och slutar med outer joins om man inte väljer ut saker i flera steg. |
||
![]() |
![]() |
Svara |
|
|