Oracle
 sql >> Baza danych >  >> RDS >> Oracle

Jak mogę znaleźć pudełko o odpowiednim rozmiarze dla każdego produktu?

Kluczem jest oczywiście połączenie dwóch stołów. Najpierw pokazuję je osobno, a nie całe zapytanie, aby pomóc w zrozumieniu. Dla każdego przedmiotu znajdujemy WSZYSTKIE rozmiary pudełek, które mogą pomieścić przedmiot.

We wszystkich przypadkach dopasowanie jest możliwe, jeśli wysokość produktu <=wysokość pudełka, a pozostałe dwa wymiary pasują do siebie w dowolnej kombinacji (produkty zawsze można obracać pasują do pudełka, niezależnie od tego, czy można je układać, czy nie).

Tylko w przypadku produktów do układania, możemy obracać produkt we wszystkich trzech wymiarach, aby zmieścić go w pudełkach. Oznacza to, że tylko w przypadku produktów do układania możemy porównać szerokość lub głębokość produktu z wysokością pudełka i porównać dwa pozostałe wymiary produktu z szerokością i głębokością pudełka.

Kiedy zrozumiemy to, co właśnie powiedziałem (tak jak zrobilibyśmy to bez komputerów, tylko ołówkiem na papierze), tłumaczenie na kod jest prawie automatyczne:

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

Wyjście:

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      

Dla każdego produktu znaleźliśmy WSZYSTKIE rozmiary, które by działały.

Zwróć uwagę na sprzężenie zewnętrzne w zapytaniu, aby uwzględnić produkty, które nie mieszczą się w DOWOLNYM rozmiarze pudełka; tak jest w przypadku produktu j , który pojawia się na końcu danych wyjściowych. Zauważ, że używam null jako znacznik „niedostępne " - słowa "niedostępne" nie dodają żadnych cennych informacji w porównaniu z prostym użyciem null .

Następnym krokiem jest prosta agregacja - dla każdego produktu znajdź najmniejszy rozmiar, który działa. Najlepszym narzędziem do tego jest FIRST funkcja agregująca (używana poniżej). Musimy zamówić według rozmiaru pudełka; ponieważ rozmiary to S, M, L (które są w odwrotnej kolejności alfabetycznej tylko przez przypadek), używam decode() funkcja przypisania 1 do S, 2 do M, 3 do L. Zapytanie zbiorcze znajduje „pierwszy” rozmiar, który działa dla każdego produktu.

Ważną rzeczą tutaj jest to, że zapytanie można łatwo uogólnić na dowolną liczbę możliwych "rozmiarów pudełek" - nawet jeśli nie wszystkie trzy wymiary są ułożone w rosnącej kolejności. (Możesz również mieć pudełka, w których tylko jeden z wymiarów jest bardzo duży, podczas gdy inne są małe itp.). Możesz zamówić według objętości pudełka lub możesz przechowywać w tabeli pudeł kolejność preferencji, równoważna temu, co robię w zapytaniu za pomocą decode() funkcja.

W końcu zapytanie i wyjście wyglądają tak. Zauważ, że użyłem nvl() w select klauzula generująca 'not available' dla ostatniego elementu, na wypadek, gdybyś naprawdę go potrzebował (w co wątpię, ale to nie jest mój problem biznesowy).

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. Zmiany Asa Wyroczni

  2. Jak wyświetlić wyniki procedury poza nią w Oracle?

  3. ORA-01002:pobierz poza sekwencją C++

  4. oracledb łączenie w łańcuch wywołań sql za pomocą obietnic

  5. Historia impasów w Oracle?