Ska hämta ut lite information ur en databas, och funderar på om jag krånglar till det. Borde gå att förenkla lite... <b>>Om man tittar på:Gör jag ett steg för mycket?
Vi har en tabell "Projekt" och en tabell "Plan".
Varje projekt kan ha flera planer (och det är naturligtvis lite annan blandad information på Plan och Projekt), så vi har:
Projekt
--------
ProjID
Plan
-----
PlanID
ProjID
x
y
z
Det finns nu ett antal "kategorier" av planer, som dynamiskt kan bestämmas av x, y och z. (Det har med bland annat med datum att göra osv.). Vi är alltid intresserade av just en sån kategori, dvs. ett visst villkor på x, y och z. Vi kan låtsas att villkoret just nu är x<y.
Vi vill nu få ut lite info om projektet tillsammans med den planen som uppfyller en viss kategori.
Det har jag löst via typ:
SELECT * FROM Projekt LEFT JOIN (SELECT * FROM Plan WHERE x<y) ON Projekt.ProjID = Plan.ProjID;
Nu är problemet att det finns många planer av samma projekt som uppfyller x<y. Då vill jag ha ut den med det högsta planID-t för varje projekt, och gör något i stil med:
SELECT ProjID, Max(PlanID) FROM (SELECT * FROM Plan WHERE x<y) GROUP BY ProjID;
Eftersom jag vill ha ut all information från de specifika planerna får jag ju vidare joina med ursprungstabellen;
SELECT * FROM Plan INNER JOIN (SELECT ProjID, Max(PlanID) FROM (SELECT * FROM Plan WHERE x<y) GROUP BY ProjID) pl ON pl.planid = plan.planid;
Redan här börjar jag fundera på om jag gör något snurrigt. Kan jag få ut samma information utan det här mecket?
Sen tillkommer ytterligare en inre grej, eftersom villkoret inte bara är x<y utan "x är den maximala som uppfyller x<y", så
(SELECT * FROM Plan WHERE x<y)
blir istället
SELECT PlanID FROM Plan INNER JOIN (SELECT ProjID, Max(x) FROM Plan WHERE x<y GROUP BY ProjID) p WHERE p.projid= plan.projid AND p.x = Plan.x
(Och i företagskulturen så har vi inga views.)
Någon som har någon bra ide om hur jag skulle kunna lösa detta snyggare?Sv: Gör jag ett steg för mycket?
Om man tittar på:
SELECT * FROM Projekt LEFT JOIN (SELECT * FROM Plan WHERE x<y) ON Projekt.ProjID = Plan.ProjID;
Är det viktigt att det är en LEFT JOIN? Vill du visa projekt som inte har någon matchande plan alltså? Om inte så kan du skriva om det såhär för att slippa en subquery:
SELECT * FROM Projekt INNER JOIN Plan ON Projekt.ProjID = Plan.ProjID WHERE x < y;
En LEFT JOIN _BORDE_ kunna skrivas såhär (lite osäker dock) samt att IFNULL/ISNULL är beroende av SQL-dialekt.
SELECT * FROM Projekt LEFT JOIN Plan ON Projekt.ProjID = Plan.ProjID WHERE x < y OR ISNULL(Plan.ProjID);
Om man tittar på:
SELECT ProjID, Max(PlanID) FROM (SELECT * FROM Plan WHERE x<y) GROUP BY ProjID;
Kan den skrivas såhär:
SELECT ProjID, Max(PlanID) FROM Plan WHERE x<y GROUP BY ProjID;
Men jag kan tyvärr inte komma på något bra sätt att få ihop allt utan subqueries när du ska plocka MAX av en kolumn.
/JohanSv:Gör jag ett steg för mycket?
SELECT * FROM Projekt LEFT JOIN (SELECT * FROM Plan WHERE x<y) ON Projekt.ProjID = Plan.ProjID;
Är det viktigt att det är en LEFT JOIN? Vill du visa projekt som inte har någon matchande plan alltså? Om inte så kan du skriva om det såhär för att slippa en subquery:
SELECT * FROM Projekt INNER JOIN Plan ON Projekt.ProjID = Plan.ProjID WHERE x < y;
</b>
Det är inte viktigt, och det är nog faktiskt så att jag istället kommer göra en koppling manuellt med datatyper i programmet, och då helt enkelt kan låta de projeketen som saknar plan av en viss typ ha typ null där.
Eftersom tabellerna är lite större än jag visar här är det svårt att få överblick, men jag tror att du har gett mig ett uppslag för hur jag kan få bort en del iaf =).