Ecco due diverse soluzioni:(Nota:ho chiamato il campo enum "package_type")
1a soluzione (tramite la funzione 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)
Questa soluzione essenzialmente prende le posizioni e le unisce al pacchetto con general (che si presume esista; quindi inner join
) e pacchetto speciale (che è opzionale; quindi left join
). Crea record come questo:
location | general-package | [special-package]
Quindi utilizza MySQL IF
funzione per tentare prima di scegliere l'ID del pacchetto speciale, quindi tornare all'ID del pacchetto generale.
2a soluzione (tramite il cast di enum in intero):
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)
Questa soluzione sfrutta il fatto che le enumerazioni vengono memorizzate come numeri interi. Esegue il cast di enum su un numero intero. special
in questo caso restituirà 2
e general
restituirà 1
. Poiché in questo caso è garantito che questi speciali siano superiori a quelli generali (cioè 2> 1), possiamo utilizzare il MAX
funzione aggregata. Ora abbiamo essenzialmente una tabella delle posizioni e il loro "pacchetto consigliato" (cioè speciale se esiste, generale altrimenti). Uniamo semplicemente questo alla query normale insieme al tipo di pacchetto previsto e restituisce i risultati corretti.
Disclaimer:non sono sicuro dell'efficienza di nessuno di questi metodi, quindi potresti provare a testarlo da solo.
Se stai cercando di riprogettare il tavolo o di denormalizzarlo per l'efficienza, penso che questo design potrebbe essere più adatto:
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
Il vantaggio sarebbe che è più facile applicare diverse regole a livello di database:
- Una posizione deve sempre avere un pacchetto generale (Items.general_package_id potrebbe essere definito come NOT NULL)
- Una sede deve avere un solo pacchetto generale (l'aggiunta in un campo anziché in un join garantisce che ce ne sia solo uno specificato)
- Una sede può avere al massimo un unico pacchetto speciale (l'aggiunta in un campo anziché in un join garantisce che ce ne sia solo uno specificato)
- Una chiave esterna su Items.general_package_id =GeneralPackages.id garantirebbe che quella colonna contenga solo pacchetti validi che sono "generali".
- La stessa cosa potrebbe essere fatta per special_package_id.
Lo svantaggio sarebbe che probabilmente dovresti usare UNION ALL ogni volta che utilizzi una delle tue vecchie query.