Mysql
 sql >> Database >  >> RDS >> Mysql

Come restituire il set di risultati in base ad altre righe

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.