Her er to forskellige løsninger:(Bemærk:Jeg kaldte enum-feltet "pakke_type")
1. løsning (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)
Denne løsning tager i det væsentlige placeringerne og forbinder den med pakken med general (som antages at eksistere; derfor inner join
) og specialpakke (som er valgfri; derfor left join
). Den opretter poster som denne:
location | general-package | [special-package]
Den bruger derefter MySQL IF
funktion til først at forsøge at vælge den særlige pakkes ID, og derefter falde tilbage til den generelle pakkes ID.
2. løsning (via støbning af enum til 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)
Denne løsning udnytter det faktum, at enums er gemt som heltal. Det kaster enum til et heltal. special
i dette tilfælde returnerer 2
og general
returnerer 1
. Fordi disse specialer garanteret er højere end generelt i dette tilfælde (dvs. 2> 1), kan vi bruge MAX
aggregeret funktion. Nu har vi i det væsentlige en tabel over lokationerne og deres "anbefalede pakke" (dvs. speciel, hvis den findes, ellers generelt). Vi føjer blot dette til den normale forespørgsel sammen med den forventede pakketype, og det returnerer de korrekte resultater.
Ansvarsfraskrivelse:Jeg er ikke sikker på effektiviteten af nogen af disse metoder, så det kan være en god ide at teste dette på egen hånd.
Hvis du ønsker enten at redesigne bordet eller at denormalisere det for effektivitet, tror jeg, at dette design kan være mere egnet:
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
Fordelen ville være, at det er lettere at håndhæve flere regler på databaseniveau:
- En lokation skal altid have en generel pakke (Items.general_package_id kunne defineres som IKKE NULL)
- En lokation må kun have en enkelt generel pakke (tilføjelse af den i et felt i stedet for en joinforbindelse garanterer, at der kun er én specificeret)
- En lokation kan højst have en enkelt speciel pakke (tilføjelse af den i et felt i stedet for en join garanterer, at der kun er én specificeret)
- En fremmednøgle på Items.general_package_id =GeneralPackages.id vil garantere, at den kolonne kun indeholder gyldige pakker, der er "generelle".
- Det samme kunne gøres for special_package_id.
Ulempen ville være, at du sandsynligvis skulle bruge en UNION ALL, hver gang du bruger en af dine gamle forespørgsler.