sql >> Databáze >  >> RDS >> Mysql

Jak vrátit sadu výsledků na základě jiných řádků

Zde jsou dvě různá řešení:(Poznámka:pole výčtu jsem nazval "package_type")

1. řešení (prostřednictvím funkce 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)

Toto řešení v podstatě vezme umístění a připojí je k balíčku s obecným (o kterém se předpokládá, že existuje; proto inner join ) a speciální balíček (který je volitelný, proto left join ). Vytváří záznamy, jako je tento:

location | general-package | [special-package]

Poté používá MySQL IF nejprve se pokusí vybrat speciální ID balíčku a poté se vrátí k obecnému ID balíčku.

2. řešení (přes přetypování enum na celé číslo):

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)

Toto řešení využívá skutečnosti, že výčty jsou uloženy jako celá čísla. Přetypuje enum na celé číslo. special v tomto případě vrátí 2 a general vrátí 1 . Protože je zaručeno, že tyto speciální jsou v tomto případě vyšší než obecné (tj. 2> 1), můžeme použít MAX agregační funkce. Nyní máme v podstatě tabulku umístění a jejich "doporučený balíček" (tj. speciální, pokud existuje, obecný jinak). Jednoduše to připojíme k normálnímu dotazu spolu s očekávaným typem balíčku a vrátí správné výsledky.

Prohlášení:Nejsem si jistý účinností žádné z těchto metod, takže to možná budete chtít vyzkoušet na vlastní kůži.

Pokud chcete stůl buď přepracovat, nebo jej denormalizovat pro efektivitu, myslím, že tento design může být vhodnější:

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

Výhodou by bylo, že je jednodušší vynutit několik pravidel na úrovni databáze:

  • Umístění musí mít vždy obecný balíček (Items.general_package_id lze definovat jako NOT NULL)
  • Umístění musí mít pouze jeden obecný balíček (jeho přidání do pole namísto spojení zaručuje, že bude zadán pouze jeden)
  • Umístění může mít nanejvýš jeden speciální balíček (jeho přidání do pole místo spojení zaručí, že bude zadán pouze jeden)
  • Cizí klíč na Items.general_package_id =GeneralPackages.id by zaručil, že tento sloupec obsahuje pouze platné balíčky, které jsou "obecné".
  • Totéž lze udělat pro special_package_id.

Nevýhodou by bylo, že byste pravděpodobně museli použít UNION ALL pokaždé, když použijete některý ze svých starých dotazů.




  1. Jak upřednostnit určité dotazy v MySQL?

  2. Jak funguje funkce LTRIM() v MySQL

  3. připojte se k mysql pomocí c#.net

  4. Připojit výsledky z dotazu ke stejnému řádku výsledků v PostgreSQL - Redshift