sql >> Databáze >  >> RDS >> Oracle

Jak najdu krabici správné velikosti pro každý produkt?

Klíčem je samozřejmě spojení mezi dvěma tabulkami. Ukážu to nejprve samostatně, spíše než celý dotaz, abych pomohl pochopit. U každé položky najdeme VŠECHNY velikosti krabic, do kterých lze položku umístit.

Ve všech případech je shoda možná, pokud výška produktu <=výška krabice a další dva rozměry se hodí v obou variantách (produkty lze vždy otočit aby se vešly do krabice, bez ohledu na to, zda jsou pokládací nebo ne).

Pouze u pokládacích výrobků je povoleno otáčet výrobek ve všech třech rozměrech, aby se vešel do krabic. To znamená, že pouze u pokládacích produktů můžeme porovnat šířku nebo hloubku produktu s výškou krabice a dva zbývající rozměry produktu porovnat se šířkou a hloubkou krabice.

Jakmile pochopíme, co jsem právě řekl (jako způsob, jakým bychom to udělali bez počítačů, jen s tužkou na papíře), překlad do kódu je téměř automatický:

select p.id, b.box_size
from   products p left outer join boxes b
       on
            p.h <= b.h and least   (p.w, p.d) <= least   (b.w, b.d)
                       and greatest(p.w, p.d) <= greatest(b.w, b.d)
       or
       p.layable = 'y'
          and
          ( p.w <= b.h and least   (p.h, p.d) <= least   (b.w, b.d)
                       and greatest(p.h, p.d) <= greatest(b.w, b.d)
            or
            p.d <= b.h and least   (p.w, p.h) <= least   (b.w, b.d)
                       and greatest(p.w, p.h) <= greatest(b.w, b.d)
          )
;

Výstup:

ID  BOX_SIZE
--- --------
a   S       
a   M       
a   L       
b   M       
b   L       
c   L       
d   S       
d   M       
d   L       
e   L       
f   L       
g   S       
g   M       
g   L       
h   M       
h   L       
i   L       
j      

U každého produktu jsme našli VŠECHNY velikosti, které by vyhovovaly.

Všimněte si vnějšího spojení v dotazu, které zahrnuje produkty, které se nevejdou do ŽÁDNÉ velikosti krabice; to je případ produktu j , který se objeví na konci výstupu. Všimněte si, že používám null jako značka pro „není k dispozici " - slova "není k dispozici" nepřidávají žádnou cennou informaci oproti jednoduchému použití null .

Dalším krokem je jednoduchá agregace – pro každý produkt najděte nejmenší velikost, která funguje. Nejlepším nástrojem je FIRST agregační funkce (jak je použita níže). Musíme objednat podle velikosti krabice; protože velikosti jsou S, M, L (které jsou náhodou v obráceném abecedním pořadí), používám decode() funkce pro přiřazení 1 k S, 2 k M, 3 k L. Souhrnný dotaz najde "první" velikost, která vyhovuje každému produktu.

Důležité je, že dotaz lze snadno zobecnit na libovolný počet možných „velikostí krabic“ – i když ne všechny tři rozměry jsou ve stoupajícím pořadí. (Můžete také mít krabice s pouze jedním z rozměrů velmi velký, zatímco ostatní jsou malé atd.). Můžete objednávat podle objemu krabic, nebo můžete skladovat v tabulce krabic pořadí preferencí, ekvivalentní tomu, co dělám v dotazu pomocí decode() funkce.

Nakonec dotaz a výstup vypadají takto. Všimněte si, že jsem použil nvl() v select klauzule ke generování 'not available' pro poslední položku, pro případ, že byste ji opravdu potřebovali (o čemž pochybuji, ale není to můj obchodní problém.)

select p.id, 
       nvl(  min(b.box_size) keep (dense_rank first 
             order by decode(b.box_size, 'S', 1, 'M', 2, 'L', 3))
          , 'not available') as box_size
from   products p left outer join boxes b
       on
            p.h <= b.h and least   (p.w, p.d) <= least   (b.w, b.d)
                       and greatest(p.w, p.d) <= greatest(b.w, b.d)
       or
       p.layable = 'y'
          and
          ( p.w <= b.h and least   (p.h, p.d) <= least   (b.w, b.d)
                       and greatest(p.h, p.d) <= greatest(b.w, b.d)
            or
            p.d <= b.h and least   (p.w, p.h) <= least   (b.w, b.d)
                       and greatest(p.w, p.h) <= greatest(b.w, b.d)
          )
group  by p.id
;

ID  BOX_SIZE
--- --------
a   S       
b   M       
c   L       
d   S       
e   L       
f   L       
g   S       
h   M       
i   L       
j   not available   


  1. MySQL indexy a pořadí

  2. opravit dotaz mysql pro vrácení náhodného řádku v rámci podskupiny

  3. JDBC Vyberte velikost dávek/načítání pomocí MySQL

  4. Hodnoty Postgres ORDER BY v seznamu IN pomocí Rails Active Record