2010-06-29 33 views
6

Tôi đang thiết kế một hệ thống hàng tồn kho, nó có người dùng, sản phẩm, buy_leads, lệnh (buy_leads được uỷ quyền), đầu vàođầu ra.Truy vấn SQL kho lưu trữ không có UNION?

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 

Đầu vào và đầu ra có một lượng giá trị. Để có được sản phẩm hàng tồn khocụ tồn kho sản phẩm tôi sử dụng UNION trong hai truy vấn SQL liệu, bằng cách làm cho đầu ra lượng tiêu cực, và sau đó nhóm và tổng hợp chúng lại với nhau:

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 

Nó hoạt động, nhưng tôi muốn sử dụng tính năng named_scope của để truy vấn chuỗi trong ActiveRecord và có thể làm những việc như:

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

ý tưởng Bất kỳ, hay tôi h ave để thay đổi lược đồ cho một lược đồ thuận tiện hơn? Cảm ơn!

Trả lời

2

Có quá nhiều khả năng để giải quyết vấn đề này, bạn muốn chính xác những gì từ các báo cáo này?

đơn đặt hàng? các sản phẩm? đầu vào/đầu ra?

(Tôi gửi bài này như một câu trả lời vì tôi không thể bình luận về câu hỏi của bạn, tôi sẽ cập nhật với câu trả lời nếu bạn có thể hài lòng soi sáng cho tôi)

CẬP NHẬT

thử này

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

và bạn có thể nhận các thông tin đầu vào khớp với id sản phẩm đó bằng cách gọi

Input.by_product(25) 

nếu đó là những gì bạn đang tìm kiếm, tôi nghĩ bạn có thể quản lý để tạo đầu ra theo sản phẩm bây giờ:]

+0

(đầu vào - đầu ra), theo Sản phẩm –

0

tôi không thể kiểm tra điều này không có dữ liệu nhưng tôi nghĩ rằng Nó phải là một cái gì đó như thế này:

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

giải pháp Victor của thất bại khi có nhiều "đầu ra" hồ sơ vì tham gia sẽ lặp lại trong các sản phẩm của cả hai đầu vào và các đầu ra.

Thay vào đó, bạn nên THAM GIA sử dụng bảng có nguồn gốc thay vì bảng thực tế. Nếu không có dữ liệu này là khó khăn để thử nghiệm và chứng minh nhưng bạn cần phải cố gắng một cái gì đó như thế này:

"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 

Bạn thấy rằng bạn đang tham gia tổng tổng hợp của bảng đầu ra, nhóm lại theo id đầu vào, chứ không phải là đầu ra bảng chính nó. Điều này giúp loại bỏ các bản sao hàng không mong muốn trong các kết nối của bạn. Tất nhiên, bạn có thể thêm nhiều phần tử vào danh sách "BẬT" hoặc mệnh đề "Ở đâu" của bảng dẫn xuất (mà tôi gọi là "z") Điều này sẽ giúp bạn tận dụng tối đa. Cách khác, đăng lên sơ đồ DB để chúng tôi hiểu các mối quan hệ bảng của bạn tốt hơn.

+0

cả hai cách tiếp cận có vẻ đúng, nhưng chúng không đơn giản hơn, tôi muốn sử dụng tên Phạm vi –

+0

để đặt truy vấn vào quy trình được lưu trữ? Tôi đoán tôi không chắc chắn những gì bạn đang tìm kiếm? – Matthew

Các vấn đề liên quan