Ето две различни решения:(Забележка:нарекох полето за изброяване "package_type")
1-во решение (чрез функцията 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)
Това решение по същество взема местоположенията и го присъединява към пакета с general (за който се предполага, че съществува; следователно inner join
) и специален пакет (който е по избор; следователно left join
). Той създава записи като този:
location | general-package | [special-package]
След това използва MySQL IF
функция, за да се опита първо да избере идентификатора на специален пакет и след това да се върне към общия идентификатор на пакета.
2-ро решение (чрез прехвърляне на enum към цяло число):
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)
Това решение използва факта, че изброяванията се съхраняват като цели числа. Прехвърля изброяването към цяло число. special
в този случай ще върне 2
и general
ще върне 1
. Тъй като тези специални в този случай гарантирано са по-високи от общите (т.е. 2> 1), можем да използваме MAX
агрегатна функция. Сега по същество имаме таблица с местоположенията и техния „препоръчан пакет“ (т.е. специален, ако съществува, общ в противен случай). Просто присъединяваме това към нормалната заявка заедно с очаквания тип пакет и то връща правилните резултати.
Отказ от отговорност:Не съм сигурен за ефективността на нито един от тези методи, така че може да искате да тествате това сами.
Ако искате или да преработите таблицата, или да я денормализирате за ефективност, мисля, че този дизайн може да е по-подходящ:
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
Предимството би било, че е по-лесно да се наложат няколко правила на ниво база данни:
- Местоположението винаги трябва да има общ пакет (Items.general_package_id може да бъде дефиниран като НЕ NULL)
- Местоположението трябва да има само един общ пакет (добавянето му в поле, а не в присъединяване гарантира, че има само един посочен)
- Дано местоположение може да има най-много един специален пакет (добавянето му в поле, а не в присъединяване гарантира, че има само един посочен)
- Външен ключ в Items.general_package_id =GeneralPackages.id ще гарантира, че тази колона съдържа само валидни пакети, които са „общи“.
- Същото нещо може да се направи и за special_package_id.
Недостатъкът би бил, че вероятно ще трябва да използвате UNION ALL всеки път, когато използвате някоя от старите си заявки.