2013-07-01 8 views
8

Non sono sicuro se quanto segue possa essere fatto usando una semplice istruzione select, ma ho due tabelle (troncate con i dati necessari al problema).Complicated Query

Inventario

  • id int (primario)
  • quantità int

Archivio - Contiene cambiamenti nel magazzino del articolo di magazzino (storia di magazzino)

  • id int (PRIMARIO)
  • inventory_item_id int (chiave esterna)
  • quantità int
  • creato datetime

Il quantità in azione è il cambio di magazzino, whil e la quantità in articolo di magazzino è la quantità corrente di tale elemento

TUTTO NEL running COLONNA RITORNERÀ 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 

LA QUESTIONE

Ora, quello che vorrei sapere è : È possibile selezionare tutte le date nella tabella stock in cui la quantità corrente di inventory_item diventa mai pari a zero utilizzando un SELECT?

So che questo può essere fatto a livello di programmazione semplicemente selezionando tutti i dati di magazzino in un articolo e sottraendo la quantità di magazzino individualmente dalla quantità di articoli di inventario corrente, che otterrà la quantità prima che il cambiamento in magazzino si sia verificato. Posso farlo con un SELECT?

+0

Ci sarà mai più di un record per una data combinazione di inventory_item_id e creato? –

risposta

2

mio prendere su di esso:

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; 

Questo ha il vantaggio relativo di dover dare un solo pass per la tabella azionario.A seconda delle dimensioni e degli indici su di esso che può o non può essere una buona cosa.

5

(Aggiornato) Supponendo non ci sarà mai più di un record per una data combinazione di inventory_item_id e ha creato, provare:

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

Poiché i.quantity è l'ultima quantità, questo non è corretto. Penso che sia necessario cambiare il campo 'running' in' SUM (s2.quantity) '. Quindi ciò restituirà i risultati corretti per tutte le date di magazzino, non solo le ultime. – Tom

+1

@ Tom: ho modificato la query per tenere conto del punto che hai sollevato. Sarebbe scorretto usare la somma della 'stock.quantity' da sola come totale parziale, dato che è usato per contenere * cambiamenti * in quantità detenute in magazzino - sommando ci dirà quanti cambiamenti ci sono stati, ma non qual era il livello delle scorte al momento. –

+0

Stavo assumendo la somma della quantità di stock.è stato il totale parziale perché ha detto: "La quantità in magazzino è la variazione di magazzino, mentre la quantità nell'articolo di magazzino è la quantità corrente di quell'articolo TUTTO NELLA COLONNA IN CORSO RITORNERÀ 0 ". Forse sto interpretando questo torto? Ho pensato che la prima entrata in classifica sarebbe stata l'azione iniziale. – Tom

2

Il modo più logico per farlo è con una somma cumulativa. Ma MySQL non supporta questo.

L'approccio più chiaro, a mio parere, è utilizzare una sottoquery correlata per ottenere la quantità corrente. Poi si tratta di una semplice questione di una clausola where per selezionare dove è 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

Credo che questo sia un approccio semplice a questo.

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

ho avuto una risposta simile basata su un totale parziale per essere contrassegnato found here...

Si può fare con @variables MySQL, ma ha bisogno di essere pre-interrogato e ha ordinato dai dati di attività dei dati. .. quindi imposta una bandiera su ogni riga che causa il negativo e tieni solo quelli. Qualcosa di simile

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 

In questo modo, per ogni articolo di magazzino, funziona a ritroso per data di creazione (ordine da parte del discendente creato per ogni ID). Quindi, quando l'ID inventario cambia, guarda il campo "Quantità" della tabella scorte per INIZIO il conteggio delle scorte esaurite. Se lo stesso ID dell'ultimo record è stato elaborato, utilizzare il saldo corrente e sottrarre la quantità di quella voce di magazzino.

Problemi correlati