sql >> Database teknologi >  >> RDS >> Oracle

Hvordan finder jeg den rigtige størrelse boks til hvert produkt?

Nøglen er selvfølgelig sammenføjningen mellem de to borde. Jeg viser det separat først, snarere end hele forespørgslen, for at hjælpe med forståelsen. For hver vare finder vi ALLE kassestørrelser, der kan rumme varen.

I alle tilfælde er matchningen mulig, hvis produkthøjde <=kassehøjde, og de to andre dimensioner passer, i begge permutationer (produkter kan altid roteres til at passe i kassen, uanset om de kan lægges eller ej).

Kun for læggebare produkter har vi lov til at rotere produktet i alle tre dimensioner for at passe dem i kasser. Det betyder, at vi kun for produkter, der kan lægges, kan sammenligne produktbredde eller -dybde med kassehøjde og sammenligne de to resterende dimensioner af produktet med kassebredde og -dybde.

Når vi først forstår, hvad jeg lige har sagt (som den måde, vi ville gøre dette uden computere, bare med blyant på papir), er oversættelsen til kode næsten automatisk:

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)
          )
;
 

Output:

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

For hvert produkt fandt vi ALLE de størrelser, der ville fungere.

Bemærk den ydre sammenføjning i forespørgslen, for at inkludere produkter, der ikke passer i NOGEN boksstørrelse; det er tilfældet med produkt j , som vises i slutningen af ​​outputtet. Bemærk, at jeg bruger null som en markør for "ikke tilgængelig " - ordene "ikke tilgængelig" tilføjer ingen værdifuld information i forhold til den simple brug af null .

Næste trin er en simpel sammenlægning - for hvert produkt skal du finde den mindste størrelse, der virker. Det bedste værktøj til dette er FIRST aggregeret funktion (som brugt nedenfor). Vi skal bestille efter kassestørrelse; da størrelserne er S, M, L (som er i omvendt alfabetisk rækkefølge ved et tilfælde), bruger jeg decode() funktion til at tildele 1 til S, 2 til M, 3 til L. Den samlede forespørgsel finder den "første" størrelse, der virker for hvert produkt.

Det vigtige her er, at forespørgslen let kan generaliseres til et hvilket som helst antal mulige "kassestørrelser" - selv når ikke alle tre dimensioner er i stigende rækkefølge. (Du kan også have kasser med kun en af ​​dimensionerne meget stor, mens de andre er små osv.). Du kan bestille efter kassevolumen, eller du kan gemme i kassetabellen en præferencerækkefølge, svarende til hvad jeg gør i forespørgslen med decode() funktion.

I sidste ende ser forespørgslen og outputtet sådan ud. Bemærk, at jeg brugte nvl() i select klausul for at generere 'not available' for den sidste vare, hvis du virkelig har brug for den (hvilket jeg tvivler på, men det er ikke mit forretningsproblem.)

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. Et hurtigt kig på SQL Server numeriske funktioner

  2. Systemvariablen MESSAGE_TEXT fungerer ikke med SIGNAL-sætningen i Mysql?

  3. SQL select where not i underforespørgsel returnerer ingen resultater

  4. Hvordan bygger man en 'relaterede spørgsmål'-motor?