Här är två olika lösningar:(Obs! Jag kallade enum-fältet "package_type")
Första lösningen (via IF()-funktionen):
select
i.location,
if(ps.id is not null, ps.id, pg.id) as package_id
from
(select distinct location from Items) i
inner join
(select i.location, p.id
from Items i
inner join Packages p on (i.package_id = p.id and p.package_type = 'general')
) pg on (i.location = pg.location)
left join
(select i.location, p.id
from Items i
inner join Packages p on (i.package_id = p.id and p.package_type = 'special')
) ps on (i.location = ps.location)
Denna lösning tar i huvudsak platserna och ansluter den till paketet med general (som antas existera; därav inner join
) och specialpaket (vilket är valfritt; därav left join
). Det skapar poster som detta:
location | general-package | [special-package]
Den använder sedan MySQL IF
funktion för att först försöka välja specialpaketets ID och faller sedan tillbaka till det allmänna paketets ID.
Andra lösning (via gjutning av enum till heltal):
select i.location, p.id
from
(select i.location, max(cast(package_type as unsigned)) as package_type
from Items i
left join Packages p on (i.package_id = p.id)
group by location
) i
inner join
(select i.location, p.id, p.package_type
from Items i
inner join Packages p on (i.package_id = p.id)
) p on (i.location = p.location and i.package_type = p.package_type)
Denna lösning utnyttjar det faktum att enums lagras som heltal. Den kastar uppräkningen till ett heltal. special
i detta fall returnerar 2
och general
returnerar 1
. Eftersom dessa special är garanterat högre än generella i detta fall (dvs. 2> 1), kan vi använda MAX
aggregerad funktion. Nu har vi i princip en tabell över platserna och deras "rekommenderade paket" (dvs. speciellt om det finns, generellt annars). Vi kopplar helt enkelt detta till den normala frågan tillsammans med den förväntade pakettypen, och det returnerar de korrekta resultaten.
Ansvarsfriskrivning:Jag är inte säker på effektiviteten hos någon av dessa metoder, så du kanske vill testa detta på egen hand.
Om du funderar på att antingen göra om bordet eller avnormalisera det för effektivitet, tror jag att denna design kan vara mer lämplig:
GeneralPackages table
id, name
1, General Package 1
SpecialPackages table
id, name
1, Special Package 1
2, Special Package 2
Items table
id, general_package_id, special_package_id, location
1, 1, NULL, America
2, 1, 2, Europe
Fördelen skulle vara att det är lättare att tillämpa flera regler på databasnivå:
- En plats måste alltid ha ett allmänt paket (Items.general_package_id kan definieras som INTE NULL)
- En plats får bara ha ett enda allmänt paket (att lägga till det i ett fält snarare än en koppling garanterar att det bara finns ett specificerat)
- En plats kan ha högst ett enstaka specialpaket (att lägga till det i ett fält snarare än en koppling garanterar att det bara finns ett specificerat)
- En främmande nyckel på Items.general_package_id =GeneralPackages.id skulle garantera att den kolumnen bara innehåller giltiga paket som är "generella".
- Samma sak kan göras för special_package_id.
Nackdelen skulle vara att du förmodligen skulle behöva använda en UNION ALL varje gång du använder en av dina gamla frågor.