Страницы

Поиск по вопросам

воскресенье, 12 января 2020 г.

Как посчитать остатки склада(объединение 2 запросов)

#sql #firebird


На Firebird 2.5 server в БД есть таблицы: goods, income, sale.   

Goods: goods_id, name    
Income: Income_id, Goods_id, incomeqty (quantity), recdate     
Sale: sales_id,income_id,Goods_id,saleqty,recdate


Есть запрос,который выбирает приходы,расходы и остатки(разницу) во временном интервале:

SELECT g.name, g.goods_id, 
       coalesce(dt2.sum_income,0), 
       coalesce(dt2.sum_sales,0),
       coalesce(dt2.differ_between,0)
FROM goods g
LEFT JOIN
(SELECT goods_id,
   sum(sum_income) as sum_income,
   sum(sum_sale) as sum_sale,
   sum(sum_income - sum_sale) as differ_between
 from (select goods_id, sum(incomeqty) as sum_income, 0 as sum_sale, 'income' as which
      from income
      where income.recdate between :d1 and :d2         
      group by goods_id
    union all
      select goods_id, 0, sum(salesqty), 'sale'
      from sales
      where sale.recdate between :d1 and :d2 
      group by goods_id) dt1
 group by goods_id
) dt2 on g.goods_id = dt2.goods_id


Но я хочу в нём добавить стартовые остатки.
стартовые остатки до интервала времены =sum(прыходы) до интервала времены-sum(расходы)
до интервала времены.
Конечные остатки в конце интервала времены=стартовые остатки+прыходы в интервале-расходы
в интервале.
стартовые остатки по-моему должен получить так:

select income.goods_id, sum(incomeqty) as start_income, 0 as start_sale, 'income'
as which
            from income
            where income.recdate < :d1
            group by goods_id
          union all
            select goods_id,0, sum(saleqty) as start_sale, 'sale'
            from sale
            where sale.recdate < :d1
            group by goods_id
         group by goods_id


Где и как включить в главном запросе запрос получения стартовых остатков?

UPDATE 1:

переделал запрос,но почему-то конечные остатки неправильно получаю(endqnt): 5000+1000-20-5=6000?

    SELECT
    G.Name,
    G.Doods_id,
    coalesce(dt2.startqnt,0) as startqnt,      
    coalesce(dt2.income,0)as income, 
    coalesce(dt2.sales,0)as sales,
    coalesce(dt2.writeoff,0)as writeoff,
    coalesce(dt2.endqnt,0) as endqnt
FROM Goods G
LEFT JOIN
(select                                                                            --dt2
     Pr_k,
     sum(startincome) as startincome,                                           
               --приходы до 
     sum(startsale) as startsale,                                               
                    --продажи до
     sum(startwriteoff) as startwriteoff,                                       
                 --списывание до
     sum(income) as income,                                                     
                  --приходы в интервале  
     sum(sale) as sales,                                                        
                      --продажи в интервале 
     sum(writeoff) as writeoff,                                                 
                     --списывание в интервале 
     sum(startincome-startsale-startwriteoff) as startqnt,                      
         --остатки стартовые 
     sum(startincome-startsale-startwriteoff+income-sale-writeoff) as endqnt    --конечные
остатки
from(                                                                       

   select 
 i.goods_id,
 sum(case when i.recdate<'01/01/2010' then i.incomeqty end) as startincome,
 0,
 0,                                       --списывание товара
 sum(case when i.recdate between '01/01/2010'  and '01/01/2020' then i.incomeqty
end) as income,
 0,
 0,
'income' as which
from income i
where i.recdate <='01/01/2020'
group by goods_id

  union all

select
s.goods_id,
0,
sum(case when s.recdate<'01/01/2010' then s.saleqty end) as startsale,
0,
0,
sum(case when s.recdate between '01/01/2010' and '01/01/2020' then 
s.saleqty end) as sale,
0,
'sale'
from sale s
where s.recdate <= '01/01/2020'
group by goods_id

 union all

select
w. goods_id,
0, 
0,
sum(case when w.writeoffDate<'01/01/2010' then w.writeoffQty end) as 
startwriteoff,
0,
0,
sum(case when w.writeoffDate between '01/01/2010' and '01/01/2020' then 
w.writeoffQty end) as writeoff,
'writeoff'
from writeoff w
where w.writeofDate < '01/01/2020'
group by goods_id) dt1
group by Goods_id )dt2
on G.Goods_id=dt2.Goods_id  


Derived Table DT1 и конечный запрос дают такой результат:


UPDATE 2

Причина была в NULL. Везде надо преврашать NULL в 0:

  SELECT
        G.Name,
        G.Doods_id,
        coalesce(dt2.startqnt,0) as startqnt,      
        coalesce(dt2.income,0)as income, 
        coalesce(dt2.sales,0)as sales,
        coalesce(dt2.writeoff,0)as writeoff,
        coalesce(dt2.endqnt,0) as endqnt
    FROM Goods G
    LEFT JOIN
    (select                                                                     
      --dt2
         Pr_k,
         sum(startincome) as startincome,                                       
                   --приходы до 
         sum(startsale) as startsale,                                           
                        --продажи до
         sum(startwriteoff) as startwriteoff,                                   
                     --списывание до
         sum(income) as income,                                                 
                      --приходы в интервале  
         sum(sale) as sales,                                                    
                          --продажи в интервале 
         sum(writeoff) as writeoff,                                             
                         --списывание в интервале 
         sum(coalesce(startincome,0)-coalesce(startsale,0)-coalesce(startwriteoff,0)
as startqnt,                                --остатки стартовые 
         sum(coalesce(startincome,0)-coalesce(startsale,0)-coalesce(startwriteoff,0)+coalesce(income,0)-coalesce(sale,0)-coalesce(writeoff,0))
as endqnt    --конечные остатки
    from(                                                                       

       select 
     i.goods_id,
     sum(case when i.recdate<'01/01/2010' then coalesce(i.incomeqty,0) end) as startincome,
     0,
     0,                                       --списывание товара
     sum(case when i.recdate between '01/01/2010'  and '01/01/2020' then coalesce(i.incomeqty,0)
end) as income,
     0,
     0,
    'income' as which
    from income i
    where i.recdate <='01/01/2020'
    group by goods_id

      union all

    select
    s.goods_id,
    0,
    sum(case when s.recdate<'01/01/2010' then coalesce(s.saleqty,0) end) as startsale,
    0,
    0,
    sum(case when s.recdate between '01/01/2010' and '01/01/2020' then 
    coalesce(s.saleqty,0) end) as sale,
    0,
    'sale'
    from sale s
    where s.recdate <= '01/01/2020'
    group by goods_id

     union all

    select
    w. goods_id,
    0, 
    0,
    sum(case when w.writeoffDate<'01/01/2010' then coalesce(w.writeoffQty,0) end) as 
    startwriteoff,
    0,
    0,
    sum(case when w.writeoffDate between '01/01/2010' and '01/01/2020' then 
    coalesce(w.writeoffQty,0) end) as writeoff,
    'writeoff'
    from writeoff w
    where w.writeofDate < '01/01/2020'
    group by goods_id) dt1
    group by Goods_id )dt2
    on G.Goods_id=dt2.Goods_id  

    


Ответы

Ответ 1



Для того что бы посчитать остаток в запросе необходимо убрать ограничение на первую дату анализируемого периода и добавить работы с датами в агрегирующую функцию с помощью CASE SELECT g.name, g.goods_id, coalesce(dt2.balance_before,0), --остаток на начало coalesce(dt2.sum_income,0), --приход в периоде coalesce(dt2.sum_sales,0), --рассход в периоде coalesce(dt2.differ_between,0), --разница за период coalesce(dt2.balance_after,0) --остаток на конец FROM goods g LEFT JOIN (SELECT goods_id, sum(case when sale.recdate < :d1 then sum_income - sum_sale end) balance_before, sum(case when sale.recdate between :d1 and :d2 then sum_income end) as sum_income, sum(case when sale.recdate between :d1 and :d2 then sum_sale end) as sum_sale, sum(case when sale.recdate between :d1 and :d2 then sum_income - sum_sale end) as differ_between sum(sum_income - sum_sale) as balance_after from (select goods_id, sum(incomeqty) as sum_income, 0 as sum_sale, 'income' as which from income where income.recdate <= :d2 group by goods_id union all select goods_id, 0, sum(salesqty), 'sale' from sales where sale.recdate <= :d2 group by goods_id) dt1 group by goods_id ) dt2 on g.goods_id = dt2.goods_id Так же хотелось бы обратить внимание на конструкцию sum(sum_income - sum_sale) В случае если sum_income или sum_sale равно NULL вычитание вернет NULL. Из-за этого можно получить ошибку при подведении итогов. Корректнее будет записать эту строчку в виде sum(COALESCE(sum_income,0) - COALESCE(sum_sale,0)), sum(sum_income) - sum(sum_sale)

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

Отправить комментарий