Zde jsou dvě různá řešení:(Poznámka:pole výčtu jsem nazval "package_type")
1. řešení (prostřednictvím funkce IF()):
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)
Toto řešení v podstatě vezme umístění a připojí je k balíčku s obecným (o kterém se předpokládá, že existuje; proto inner join
) a speciální balíček (který je volitelný, proto left join
). Vytváří záznamy, jako je tento:
location | general-package | [special-package]
Poté používá MySQL IF
nejprve se pokusí vybrat speciální ID balíčku a poté se vrátí k obecnému ID balíčku.
2. řešení (přes přetypování enum na celé číslo):
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)
Toto řešení využívá skutečnosti, že výčty jsou uloženy jako celá čísla. Přetypuje enum na celé číslo. special
v tomto případě vrátí 2
a general
vrátí 1
. Protože je zaručeno, že tyto speciální jsou v tomto případě vyšší než obecné (tj. 2> 1), můžeme použít MAX
agregační funkce. Nyní máme v podstatě tabulku umístění a jejich "doporučený balíček" (tj. speciální, pokud existuje, obecný jinak). Jednoduše to připojíme k normálnímu dotazu spolu s očekávaným typem balíčku a vrátí správné výsledky.
Prohlášení:Nejsem si jistý účinností žádné z těchto metod, takže to možná budete chtít vyzkoušet na vlastní kůži.
Pokud chcete stůl buď přepracovat, nebo jej denormalizovat pro efektivitu, myslím, že tento design může být vhodnější:
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
Výhodou by bylo, že je jednodušší vynutit několik pravidel na úrovni databáze:
- Umístění musí mít vždy obecný balíček (Items.general_package_id lze definovat jako NOT NULL)
- Umístění musí mít pouze jeden obecný balíček (jeho přidání do pole namísto spojení zaručuje, že bude zadán pouze jeden)
- Umístění může mít nanejvýš jeden speciální balíček (jeho přidání do pole místo spojení zaručí, že bude zadán pouze jeden)
- Cizí klíč na Items.general_package_id =GeneralPackages.id by zaručil, že tento sloupec obsahuje pouze platné balíčky, které jsou "obecné".
- Totéž lze udělat pro special_package_id.
Nevýhodou by bylo, že byste pravděpodobně museli použít UNION ALL pokaždé, když použijete některý ze svých starých dotazů.