Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Inventory SQL Query without UNION?

I'm designing an inventory system, it has users, products, buy_leads, orders (authorized buy_leads), inputs and outputs.

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

Inputs and Outputs have a quantity value. To get the products inventory, and specific product inventory I use UNION in two raw SQL queries, by making outputs quantities negative, and then group and sum them all together:

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

It works, but I would like to use named_scope's features to chain queries in ActiveRecord and be able to do things like:

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

Any ideas, or do I have to change the schema for a more convenient one ? Thanks!

like image 323
Ben Orozco Avatar asked Jun 29 '10 01:06

Ben Orozco


1 Answers

There are too many possibilities to solve this, what exactly do you want from these reports?

the buy orders? the products? the inputs/outputs?

(I'm posting this as an answer because I cannot comment on your question, I'll update with answer if you could please enlighten me)

UPDATE

try this

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

and you can get the inputs that match that product id by calling

Input.by_product(25)

if that is what you were looking for I think you can manage to make the outputs by products too now :]

like image 102
Draiken Avatar answered Oct 01 '22 01:10

Draiken