2010-06-29 16 views
6

Estoy diseñando un sistema de inventario , tiene usuarios, productos, buy_leads, órdenes (buy_leads autorizados), entradas y salidas.Inventario SQL Query sin UNIÓN?

class Product < ActiveRecord::Base 
    has_many :buy_leads 
end 

class BuyLead < ActiveRecord::Base 
    belongs_to :product 
    has_one :order 
end 

class Order < ActiveRecord::Base 
    belongs_to :buy_lead 
    belongs_to :user, :foreign_key => :authorized_by 
    has_many :inputs 
end 

class Input < ActiveRecord::Base 
    belongs_to :order 
    has_many :outputs 
end 

class Output < ActiveRecord::Base 
    # Associations 
    belongs_to :input 
    belongs_to :user 
end 

entradas y salidas tienen un valorcantidad. Para obtener el productos de inventario, y inventario de productos específicos utilizo UNION en dos consultas SQL primas, haciendo salidas cantidades negativas, y luego el grupo y sumar a todos juntos:

class InventoryController < ApplicationController 

    def index 
    @inventory = Input.find_by_sql products_inventory_sql 
    end 

    def show 
    @inventory = Input.find_by_sql product_inventory_sql(params[:id]) 
    end 

private 

    def inputs_sql 
    "SELECT b.*, p.*, i.order_id, 
      i.id AS input_id, 
      i.quantity AS quantity  
    FROM inputs i 
      JOIN orders r ON r.id = i.order_id 
      JOIN buy_leads b ON b.id = r.buy_lead_id 
      JOIN products p ON p.id = b.product_id" 
    end 

    def outputs_sql 
    "SELECT b.*, p.*, i.order_id, 
      i.id AS input_id, 
      (o.quantity * -1) AS quantity 
    FROM outputs o 
      JOIN inputs i ON i.id = o.input_id 
      JOIN orders r ON r.id = i.order_id 
      JOIN buy_leads b ON b.id = r.buy_lead_id 
      JOIN products p ON p.id = b.product_id" 
    end 

    def products_inventory_sql 
    "SELECT *, SUM(quantity) AS remaining_qty 
    FROM (#{inputs_sql} UNION #{outputs_sql}) 
    GROUP BY product_id" 
    end 

    def product_inventory_sql(id) 
    "SELECT *, SUM(quantity) AS remaining_qty 
    FROM (#{inputs_sql} UNION #{outputs_sql}) 
    WHERE product_id = #{id} 
    GROUP BY order_id, input_id" 
    end 

end 

Funciona, pero me gustaría utilizar características de named_scope a las preguntas de la cadena en ActiveRecord y ser capaz de hacer cosas como:

Product.inputs.by_product(id) 
Product.inventory.by_product(id) 
... 

Todas las ideas, o tengo h ave para cambiar el esquema por uno más conveniente? ¡Gracias!

Respuesta

2

Existen muchas posibilidades para resolver esto, ¿qué es exactamente lo que quiere de estos informes?

las órdenes de compra? ¿los productos? las entradas/salidas?

(estoy publicando esto como una respuesta porque no puedo comentar sobre su pregunta, voy a actualizar con la respuesta si pudiera por favor me ilumine)

ACTUALIZACIÓN

probar esto

#on input 
named_scope :by_product, lambda {|id| {:joins => {:orders => {:buy_leads => :products}}, :conditions => ['products.id = ?', id]}} 

y se puede obtener las entradas que coinciden con ese producto Identificación llamando

Input.by_product(25) 

si eso es lo que estabas buscando, creo que puedes hacer las salidas por productos también ahora:]

+0

(entradas - salidas), por Producto –

0

no puedo probar esto sin datos, pero creo que debe ser algo como esto:

SELECT 
     b.*, p.*, i.order_id, i.id AS input_id, i.quantity AS quantity, -o.quantity AS quantity, 
     (i.quantity - COALESCE(o.quantity,0)) AS remaining_qty 
FROM 
     products p 
     JOIN buy_leads b ON b.product_id = p.id 
     JOIN orders r ON r.buy_lead_id = b.id 
     JOIN inputs i ON i.order_id = r.id 
     LEFT JOIN outputs o ON o.input_id = i.id 
0

solución de Victor falla cuando hay múltiples registros "salida" porque la unión duplicará los productos tanto por las entradas y las salidas.

En su lugar, debe UNIRSE utilizando una tabla derivada en lugar de la tabla real. Sin datos esto es difícil de probar y demostrar, pero que debe estar tratando algo como esto:

"SELECT b.*, p.*, i.order_id, 
     i.id AS input_id, 
     i.quantity AS quantity, 
ISNULL(z.negquantities,0) negquantities, 
i.quantity + ISNULL(z.negquantities,0) sumquantities 

FROM inputs i 
     JOIN orders r ON r.id = i.order_id 
     JOIN buy_leads b ON b.id = r.buy_lead_id 
     JOIN products p ON p.id = b.product_id 
    JOIN 
    (SELECT SUM(-1 * o.quantity) NegQuantities, o.input_id FROM outputs o GROUP BY o.input_id) z 
    ON z.input_id = i.id 

Usted ve que se está uniendo a la suma total de la tabla de resultados, agrupados por el id de entrada, en lugar de la salida mesa en sí Esto elimina duplicaciones involuntarias de filas en sus uniones. Por supuesto, puede agregar más elementos a la lista "ON" o la cláusula "Where" de la tabla derivada (a la que llamé "z") Esto debería ayudarle durante la mayor parte del camino. O bien, publique un diagrama DB para que comprendamos mejor las relaciones entre las tablas.

+0

Ambos enfoques parecen ser correctos, pero no lo simplifican, quiero usar Named Scopes –

+0

así que ponga la consulta en un procedimiento almacenado? Supongo que no estoy seguro de lo que estás buscando. – Matthew