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