Oracle
 sql >> база данни >  >> RDS >> Oracle

Как мога да намеря правилния размер кутия за всеки продукт?

Ключът, разбира се, е съединението между двете таблици. Първо го показвам отделно, а не цялата заявка, за да ви помогне да разберете. За всеки артикул намираме ВСИЧКИ размери на кутията, които могат да поберат артикула.

Във всички случаи съвпадението е възможно, ако височината на продукта <=височината на кутията, а другите два измерения пасват, в която и да е пермутация (продуктите винаги могат да бъдат завъртани да се поберат в кутията, независимо дали могат да се полагат или не).

Само за продукти, които могат да се полагат, ни е позволено да завъртаме продукта във всичките три измерения, за да ги поставим в кутии. Това означава, че само за продукти, които могат да се полагат, можем да сравним ширината или дълбочината на продукта с височината на кутията и да сравним останалите два размера на продукта с ширината и дълбочината на кутията.

След като разберем какво казах току-що (както бихме направили това без компютри, само с молив върху хартия), преводът в код е почти автоматичен:

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

Изход:

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      

За всеки продукт намерихме ВСИЧКИ размери, които биха работили.

Обърнете внимание на външното съединение в заявката, за да включите продукти, които не се побират в НИКОЙ размер на кутията; такъв е случаят с продукт j , който се появява в края на изхода. Имайте предвид, че използвам null като маркер за „не е наличен " - думите "не е налично" не добавят ценна информация спрямо простото използване на null .

Следващата стъпка е просто агрегиране - за всеки продукт намерете най-малкия размер, който работи. Най-добрият инструмент за това е FIRST агрегатна функция (както се използва по-долу). Трябва да поръчаме по размер на кутията; тъй като размерите са S, M, L (които са в обратен азбучен ред съвсем случайно), използвам decode() функция за присвояване на 1 на S, 2 на M, 3 на L. Обобщената заявка намира „първия“ размер, който работи за всеки продукт.

Важното тук е, че заявката може лесно да се обобщи до произволен брой възможни "размери на кутии" - дори когато не всичките три измерения са в нарастващ ред. (Можете също така да имате кутии само с един от размерите много голям, докато другите са малки и т.н.). Можете да поръчате по обем на кутията или да съхраните в таблицата с кутии ред на предпочитание, еквивалентен на това, което правя в заявката с decode() функция.

В крайна сметка заявката и изходът изглеждат така. Имайте предвид, че използвах nvl() в select клауза за генериране на 'not available' за последния артикул, в случай че наистина имате нужда от него (в което се съмнявам, но не е мой бизнес проблем.)

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. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. Разделяне на сложен низ с помощта на регулярен израз

  2. Как да изберете колона от всички таблици, в които се намира?

  3. Функцията add_months на oracle се различава от Java

  4. Колона на заявка с тип данни char в Oracle

  5. Как да внедрите удобни за потребителя идентификатори без пропуски в NHibernate?