Aquí hay dos soluciones diferentes:(Nota:llamé al campo de enumeración "package_type")
Primera solución (a través de la función 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)
Esta solución esencialmente toma las ubicaciones y las une al paquete con general (que se supone que existe; por lo tanto, inner join
) y paquete especial (que es opcional; por lo tanto, left join
). Crea registros como este:
location | general-package | [special-package]
Luego usa MySQL IF
función para intentar primero elegir la ID del paquete especial y luego recurrir a la ID del paquete general.
Segunda solución (a través de conversión de enumeración a entero):
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)
Esta solución aprovecha el hecho de que las enumeraciones se almacenan como números enteros. Convierte la enumeración en un entero. special
en este caso devolverá 2
y general
devolverá 1
. Debido a que se garantiza que estos especiales serán más altos que los generales en este caso (es decir, 2> 1), podemos usar el MAX
función agregada. Ahora tenemos esencialmente una tabla de las ubicaciones y su "paquete recomendado" (es decir, especial si existe, general de lo contrario). Simplemente unimos esto a la consulta normal junto con el tipo de paquete esperado y arroja los resultados correctos.
Descargo de responsabilidad:no estoy seguro de la eficacia de ninguno de estos métodos, por lo que es posible que desee probarlo por su cuenta.
Si está buscando rediseñar la tabla o desnormalizarla por eficiencia, creo que este diseño puede ser más adecuado:
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
La ventaja sería que es más fácil aplicar varias reglas a nivel de base de datos:
- Una ubicación siempre debe tener un paquete general (Items.general_package_id podría definirse como NOT NULL)
- Una ubicación solo debe tener un único paquete general (agregarlo en un campo en lugar de unirlo garantiza que solo haya uno especificado)
- Una ubicación puede tener como máximo un único paquete especial (agregarlo en un campo en lugar de unirlo garantiza que solo haya uno especificado)
- Una clave externa en Items.general_package_id =GeneralPackages.id garantizaría que esa columna solo contiene paquetes válidos que son "generales".
- Se podría hacer lo mismo para special_package_id.
La desventaja sería que probablemente necesite usar UNION ALL cada vez que use una de sus consultas anteriores.