Запрос Postgres для проверки запасов, доступных после покупки и продажи

#sql #postgresql

Вопрос:

пожалуйста, предложите мне способ ведения таблицы запасов, которая будет автоматически обновляться при вставке данных в таблицы покупок или продаж, может произойти добавление или обновление нескольких строк, на данный момент я использую приведенный ниже запрос для создания записей запасов: что-то вроде: запасы.кол-во = сумма(покупка.кол-во) — сумма(продажа.кол-во);

 select ProductName, 
       sum(PQty),
       sum(SQty),
       sum(PQty - SQty)
from (
  select p.product_name as ProductName,
         0 as SQty,
         case when sum(p.qty) is null then 0 else sum(p.qty) end as PQty from purchase p
  group by p.product_name
  
  union
  
  select s.product_name as ProductName, 
         0 as PQty, 
         case when sum(s.qty) is null then 0 else sum(s.qty) end as SQty from sell s
  group by s.product_name
) Stocks
group by ProductName;
 

Комментарии:

1. Добавление выборочных данных может быть полезным.

2. Вам действительно нужно задать вопрос получше. Мы ничего не знаем о вашей таблице запасов и не можем просто предложить вам способ что-то сделать без подробного описания проблемы, с которой вы столкнулись.

3. @James Z, на данный момент таблица запасов не поддерживается, я спрашиваю, например, как мы можем создать таблицу, которая автоматически обновляет количество продукта, как только происходит какая-либо вставка или обновление в таблице покупок или продаж, в случае совершения покупки она должна суммировать количество в таблице запасов для одного и того же продукта или сделать новую запись в таблице запасов в случае, если в ней нет одного и того же продукта, и когда продается продукт, таблица продаж обновится, и количество будет уменьшено из таблицы запасов.

4. @rezu, предположим, что в таблице покупок товар abc есть в количестве 100, а у продаж есть abc с количеством 20, тогда в таблице запасов должна быть запись с количеством abc 80, если у продаж нет записи о продукте abc, то запасы должны иметь abc в количестве 100, но если у продаж есть продукт abc с любым количеством, а у покупок нет abc, то он не появится в таблице запасов.

Ответ №1:

Чтобы получить ценность товаров, не имеющих продаж, вам нужно СЛЕВА ПРИСОЕДИНИТЬ покупки к продажам, а не пытаться объединить их. Вы можете сделать это, создав два CTE, которые получают общее количество покупок и общее количество проданных соответственно. Затем вы оставили присоединиться к CTE на product_name. Что-то вроде:

     with pur(product_name,total_purchased)  as 
         ( select product_name
                , sum(qty) 
             from purchase 
            group by product_name
         ) 
       , sal (product_name,total_sold) as   
        ( select  product_name 
                , sum(qty) 
             from sell 
            group by product_name
         )                  
    select p.Product_Name
         , p.total_purchased
         , coalesce(s.total_sold,0.00) total_sold
         , p.total_purchased -  coalesce(s.total_sold,0.00) stock
      from pur p 
      left join sal s 
        on (p.product_name = s.product_name);     
 

Это, однако, НЕ поддерживает уровни запасов, но создает подсчет на данный момент.

Я предлагаю отказаться от идеи «поддерживать таблицу запасов, которая будет автоматически обновляться …». Поскольку ведение таблицы усложняется, вам нужно обрабатывать не только вставки, но также обновления и удаления, что усложняется. Что происходит, когда покупка отменяется или в продаже есть дефектный продукт,… В основном вы храните выводимое значение, что обычно является очень плохой идеей.
Вместо этого создайте ПРЕДСТАВЛЕНИЕ, которое при необходимости предоставляет значения «подсчета в данный момент». И по самой своей природе АВТОМАТИЧЕСКИ подстраивается под любую активность на любом столе.

 create view stock( product_name   
                      , purchases     
                      , sales         
                      , current_stock  
                      ) as 
    with pur(product_name,total_purchased)  as 
         ( select product_name
                , sum(qty) 
             from purchase 
            group by product_name
         ) 
       , sal (product_name,total_sold) as   
        ( select  product_name 
                , sum(qty) 
             from sell
            group by product_name
         )                  
    select p.Product_Name
         , p.total_purchased
         , coalesce(s.total_sold,0.00) 
         , p.total_purchased -  coalesce(s.total_sold,0.00) 
      from pur p 
      left join sal s 
        on (p.product_name = s.product_name);   
 

См. демонстрацию: Для демонстрации я попытался сгенерировать данные, чтобы для любого продукта количество проданных товаров не превышало количество купленных. Однако значения генерируются с помощью функции random (), поэтому это не гарантируется.

Комментарии:

1. большое вам спасибо, это очень помогло, такое приятное и исчерпывающее объяснение.