sql >> Base de Datos >  >> RDS >> Mysql

Cómo devolver un conjunto de resultados basado en otras filas

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.