2013-07-01 13 views
8

Nie jestem pewien, czy można wykonać następujące czynności za pomocą zwykłej instrukcji select, ale mam dwie tabele (obcięte z danymi niezbędnymi do problemu).Skomplikowane zapytanie

Inventory Item

  • id int (pierwotny)
  • ilość int

Zdjęcie - Zawiera zmiany w magazynie z zapasu (historia Zdjęcie)

  • ID Int (pierwotne)
  • inventory_item_id Int (KLUCZ obcego)
  • ilość Int
  • utworzony DateTime

ilość w stada zmiana w magazynie, whil e ilość w pozycji zapasów jest obecna ilość danego elementu

wszystko w running kolumna return 0

SELECT 
inventory_item.id, 
(inventory_item.quantity - SUM(stock.quantity)) AS running 
FROM 
    stock 
     JOIN 
    inventory_item ON stock.inventory_item_id = inventory_item.id 
GROUP BY inventory_item.id 

Pytanie

Teraz, co chciałbym wiedzieć : Czy możliwe jest wybranie wszystkich dat w tabeli stanów magazynowych, w których bieżąca ilość inwentarza stanie się zero przy użyciu SELECT?

Wiem, że można to zrobić programowo, wybierając po prostu wszystkie dane o stanie magazynowym w jednym elemencie i odejmując ilość zapasów indywidualnie od ilości w bieżącym stanie zapasów, która otrzyma ilość przed zmianą stanu zapasów. Czy mogę to zrobić za pomocą SELECT?

+0

Czy kiedykolwiek znajdzie się więcej niż jeden rekord dla danej kombinacji inventory_item_id i utworzony? –

Odpowiedz

2

My się na nim:

select 
    inventory_item_id `item`, 
    created `when` 
from 
    (select 
     @total := CASE WHEN @curr <> inventory_item_id 
        THEN quantity 
        ELSE @total+quantity END as running_total, 
     inventory_item_id, 
     created,     
     @curr := inventory_item_id 
    from 
     (select @total := 0) a 
     (select @curr := -1) b 
     (select inventory_item_id, created, quantity from stock order by inventory_item_id, created asc) c 
    ) running_total 
where running_total.running_total = 0; 

Ten ma względną zaletę dać tylko jedną przepustkę do tabela zapasów.W zależności od rozmiaru i indeksów, które mogą lub nie są dobre.

5

(Aktualizacja) Zakładając, że nigdy nie będzie więcej niż jeden rekord dla danej kombinacji inventory_item_id i stworzył, spróbuj:

SELECT i.id, 
     s.created, 
     i.quantity - COALESCE(SUM(s2.quantity),0) AS running 
FROM inventory_item i 
JOIN stock s ON s.inventory_item_id = i.id 
LEFT JOIN stock s2 ON s2.inventory_item_id = i.id and s.created < s2.created 
GROUP BY i.id, s.created 
HAVING running=0 
+0

Ponieważ i.quantity jest najnowszą ilością, jest to niepoprawne. Myślę, że musisz zmienić swoje pole 'running' na' SUM (s2.quantity) '. Wtedy to zwróci prawidłowe wyniki dla wszystkich dat zapasów, a nie tylko najnowsze. – Tom

+1

@ Tom: Poprawiłem zapytanie, aby uwzględnić podniesiony punkt. Niepoprawne byłoby używanie sumy samego "stock.quantity" jako sumy bilansowej, ponieważ służy ona do przechowywania * zmian * w ilościach przechowywanych na magazynie - podsumowując, powiedziałaby nam, ile było tam zmian, ale nie jaki był poziom zapasów w danym czasie. –

+0

Zakładałem, że suma akcji. Kwota była całkowita, ponieważ powiedział: "Ilość na stanie to zmiana w magazynie, podczas gdy ilość w elemencie zapasowym to bieżąca ilość tej pozycji WSZYSTKO W KOLUMNIE POWRÓT 0 ". Być może interpretuję to źle? Doszedłem do wniosku, że pierwszy wpis na giełdzie będzie początkiem. – Tom

2

najbardziej logicznym sposobem, aby to zrobić, to z skumulowanej sumy. Ale MySQL tego nie obsługuje.

Najbardziej oczywistym podejściem, moim zdaniem, jest użycie skorelowanego podzapytania, aby uzyskać bieżącą ilość. To jest to prosta sprawa a where klauzuli wybrać gdzie jest 0:

select i.* 
from (select i.*, 
      (select SUM(i2.inventory) 
       from inventory i2 
       where i2.inventory_item_id = i.inventory_item_id and 
        i2.created <= i.created 
      ) as RunningQuantity 
     from inventory i 
    ) i 
where RunningQuantity = 0; 
2

Uważam, że jest to proste podejście.

SELECT inventory_item.id, stock.created 

FROM inventory_item 

     JOIN stock ON stock.inventory_item_id = inventory_item.id 

WHERE (SELECT SUM(quantity) FROM stock WHERE created <= stock.created) = 0 
2

miałem podobną odpowiedzią na podstawie uruchomionego sumie być oflagowane found here...

Można zrobić z @variables MySQL, ale dane muszą być wstępnie pytani i sortowane według danych działalności. .. następnie ustaw flagę w każdym wierszu, który powoduje ujemne i zachowaj tylko te. Coś jak

select 
     PreQuery.* 
    from 
     (select 
       s.id, 
       s.created, 
       @runBal := if(s.id = @lastID, @runBal - quantity, @i.quantity) as CurBal, 
       @lastID := s.id as IDToCompareNextEntry 
      from 
       stock s 
       join inventory_item ii 
        on s.inventory_item_id = ii.id, 
       (select @lastID := -1, 
         @runBal := 0) sqlvars 
      order by 
       s.id, 
       s.created DESC) PreQuery 
    where 
     PreQuery.CurBal < 0 

ten sposób dla każdej pozycji zapasów, to działa wstecz od daty utworzenia (zlecenia przez utworzonego Malejąco Na ID). Tak więc, gdy ID inwentarza się zmieni, spójrz do pola "Ilość" tabeli spisu, aby rozpocząć spisywanie zużytego towaru. Jeśli jest to ten sam identyfikator co przetworzony ostatni rekord, po prostu użyj salda bieżącego i odejmij ilość tego wpisu giełdowego.

Powiązane problemy