SQL Server: подзапрос, чтобы вернуть последнюю версию стоимости единицы инвентаря в наличии - PullRequest
0 голосов
/ 09 июня 2019

У меня есть 2 таблицы, которые я пытаюсь объединить, чтобы получить результат, который сообщает мне стандартную стоимость предмета, который все еще находится в распоряжении (на основе метода оценки FIFO).Первая таблица - это квитанции об инвентаризации, в которой указываются оставшиеся детали и даты транзакций с этими квитанциями.Второе - это стандартное представление затрат, которое сообщает мне историю затрат элемента (rev = номер редакции, который увеличивается на 1 каждый раз, когда обновляется стандартная стоимость детали).

В настоящее время у меня есть решение, которое работаетиспользуя ТОП 1 и упорядочение по DESC на дату вступления в силу стоимости, однако, когда я запускаю это для всего инвентарного списка компании, это занимает более 16 минут из-за неэффективности подзапроса ТОП 1 и стоимости.

Примерные данные (инвентарные поступления в наличии):

partID  warehouse     transDate  seqn orderID   qtytoconsume
-------------------------------------------------------------
P0003   W01 2019-01-24 00:00:00.000 1   ORD0187 2
P0003   W01 2018-06-24 00:00:00.000 1   ORD0099 3
P0003   W01 2018-11-24 00:00:00.000 1   ORD0165 1
P0003   W04 2018-12-14 00:00:00.000 1   ORD0175 1
P0002   W02 2019-01-14 00:00:00.000 1   ORD0184 4
P0002   W02 2019-03-24 00:00:00.000 1   ORD0199 1
P0002   W03 2018-05-27 00:00:00.000 1   ORD0093 1
P0002   W03 2018-12-06 00:00:00.000 1   ORD0171 2
P0001   W04 2018-09-09 00:00:00.000 1   ORD0146 5
P0001   W02 2019-04-22 00:00:00.000 1   ORD0200 4
P0001   W03 2019-03-29 00:00:00.000 1   ORD0200 2
P0001   W02 2018-02-14 00:00:00.000 1   ORD0061 1

и стандартное представление затрат:

partID  document    effdate            rev  costamt
-----------------------------------------------------
P0001   IV0001  2018-01-28 00:00:00.000 1   1000.00
P0001   IV0023  2018-06-30 00:00:00.000 2   1200.00
P0001   IV0045  2019-01-01 00:00:00.000 3   1300.00
P0002   IV0001  2018-01-28 00:00:00.000 1   45.00
P0002   IV0013  2018-04-10 00:00:00.000 2   42.00
P0002   IV0045  2019-01-01 00:00:00.000 3   56.00
P0003   IV0001  2018-01-28 00:00:00.000 1   23400.00
P0003   IV0003  2018-02-20 00:00:00.000 2   11200.00
P0003   IV0045  2019-01-01 00:00:00.000 3   15000.00
P0003   IV0047  2019-02-27 00:00:00.000 4   13400.00
P0003   IV0078  2019-05-03 00:00:00.000 5   14670.00

И мой результат (равный моему ожидаемому результату), но для больших наборов строкменьше, чем идеал.

partID  warehouse   transDate     seqn  orderID qty costamt
-------------------------------------------------------------
P0003   W01 2019-01-24 00:00:00.000 1   ORD0187 2   15000.00
P0003   W01 2018-06-24 00:00:00.000 1   ORD0099 3   11200.00
P0003   W01 2018-11-24 00:00:00.000 1   ORD0165 1   11200.00
P0003   W04 2018-12-14 00:00:00.000 1   ORD0175 1   11200.00
P0002   W02 2019-01-14 00:00:00.000 1   ORD0184 4   56.00
P0002   W02 2019-03-24 00:00:00.000 1   ORD0199 1   56.00
P0002   W03 2018-05-27 00:00:00.000 1   ORD0093 1   42.00
P0002   W03 2018-12-06 00:00:00.000 1   ORD0171 2   42.00
P0001   W04 2018-09-09 00:00:00.000 1   ORD0146 5   1200.00
P0001   W02 2019-04-22 00:00:00.000 1   ORD0200 4   1300.00
P0001   W03 2019-03-29 00:00:00.000 1   ORD0200 2   1300.00
P0001   W02 2018-02-14 00:00:00.000 1   ORD0061 1   1000.00

Мой запрос:

SELECT 
    ioh.*, sc.costamt, sc.effdate
FROM
    inventoryonHand ioh
LEFT JOIN 
    standardcosts sc ON sc.partID = ioh.partID
                     AND sc.effdate = (SELECT TOP 1 sc2.effDate
                                       FROM standardcosts sc2
                                       WHERE sc2.partID = sc.partID
                                         AND sc2.effDate < ioh.transDate
                                       ORDER BY sc2.partID ASC, sc2.effDate DESC);

Большое спасибо, ребята!

Ответы [ 3 ]

1 голос
/ 09 июня 2019

Вы можете попробовать его (если вы считаете, что partID и transdate могут быть уникальными в вашей таблице инвентаризации, иначе используйте раздел по его ключу):

select * from (
   select f1.*, 
   f2.effdate, f2.costamt, f2.rev,
   row_number() over(partition by f1.partid, f1.transdate order by f2.effdate desc, f2.rev desc) as lasteffDaterank
   from inventoryonHand f1
   left outer join standardcosts f2 on f1.partid=f2.partid and f2.effDate < f1.transDate
) tmp 
where lasteffDaterank=1
1 голос
/ 09 июня 2019

Ты тоже можешь это сделать, но на самом деле не лучше;)

select f1.*, f3.*
from inventoryonHand f1
outer apply
(
  select top 1 f2.costamt from standardcosts f2 
  where f1.partid=f2.partid and f2.effDate < f1.transDate
  order by f2.effdate desc, f2.rev desc
) f3
1 голос
/ 09 июня 2019

Вы можете попытаться упростить подзапрос, используя max().

(SELECT max(sc1.effdate)
        FROM standardcosts sc2
        WHERE sc2.partid = sc.partid
              AND sc2.effdate < ioh.transdate)

Для производительности попробуйте индекс на standardcosts (partid ASC, effdate DESC).

...