Инвентаризация SQL-запросов без UNION? - PullRequest
6 голосов
/ 29 июня 2010

Я проектирую систему инвентаризации , в ней пользователей , продуктов , buy_leads , заказов (разрешенные buy_leads), входы и выходы .

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

Входы и выходы имеют значение количество . Чтобы получить инвентаризацию продуктов и инвентаризацию конкретных продуктов Я использую UNION в двух необработанных запросах SQL, делая выходные данные количества отрицательными , а затем группирую и суммирую их все вместе:

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

Это работает, но я бы хотел использовать функции named_scope для цепочки запросов в ActiveRecord и иметь возможность выполнять такие действия, как:

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

Есть идеи, или мне нужно изменить схему на более удобную? Спасибо!

Ответы [ 3 ]

2 голосов
/ 23 июля 2010

Слишком много возможностей решить эту проблему, что именно вы хотите от этих отчетов?

ордеров на покупку?продукты?входы / выходы?

(я отправляю это как ответ, потому что я не могу прокомментировать ваш вопрос, я обновлю ответ, если вы могли бы просветить меня)

ОБНОВЛЕНИЕ

попробуйте это

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

, и вы можете получить входные данные, которые соответствуют этому идентификатору продукта, позвонив по номеру

Input.by_product(25)

, если это то, что вы искалипотому что я думаю, что вы можете сделать вывод по продуктам и сейчас:]

0 голосов
/ 22 июля 2010

Решение Виктора терпит неудачу, когда имеется несколько «выходных» записей, потому что объединение будет дублировать продукты ОБА входами и выходами.

Вместо этого вам следует СОЕДИНЯТЬСЯ, используя производную таблицу вместо фактической таблицы.Без данных это сложно протестировать и продемонстрировать, но вы должны попробовать что-то вроде этого:

    "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

Вы видите, что вы объединяете совокупную сумму выходной таблицы, сгруппированную по входному идентификатору, а несама таблица вывода.Это исключает непреднамеренное дублирование строк в ваших объединениях.Конечно, вы можете добавить больше элементов в список «ON» или в предложение «Where» производной таблицы (которое я назвал «z»). Это поможет вам в этом.Также можно опубликовать диаграмму БД, чтобы мы лучше понимали ваши связи с таблицами.

0 голосов
/ 22 июля 2010

Я не могу проверить это без данных, но я думаю, что это должно быть примерно так:

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
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...