T-SQL - Заполнение пробелов в текущем балансе - PullRequest
1 голос
/ 23 февраля 2012

Я работаю над проектом хранилища данных, и клиент предоставляет данные о ежедневных продажах.Доступные количества указаны в большинстве строк, но часто отсутствуют.Мне нужна помощь о том, как заполнить эти пропущенные значения на основе предыдущей информации о OH и продажах.

Вот пример данных:

Line#  Store  Item  OnHand  SalesUnits  DateKey
-----------------------------------------------
1      001    A     100     20          1       
2      001    A     80      10          2       
3      001    A     null    30          3       --[OH updated with 70 (80-10)]
4      001    A     null    5           4       --[OH updated with 40 (70-30)]
5      001    A     150     10          5       --[OH untouched]
6      001    B     null    4           1       --[OH untouched - new item]
7      001    B     80      12          2       
8      001    B     null    10          3       --[OH updated with 68 (80-12]

Строки 1 и 2 не должны обновляться, поскольку существуют количества OnHand.
Строки 3 и 4 должны обновляться на основе их предыдущих строк.
Строка 5 должна оставаться без изменений, поскольку OnHand предоставляется.
Строка 6 должна оставаться без изменений, поскольку это первая строка для Item.B

Есть ли способ сделать это в заданной операции?Я знаю, что могу легко сделать это с помощью курсора fast_forward, но это займет много времени (15M + строки).

Спасибо за вашу помощь!

1 Ответ

0 голосов
/ 23 февраля 2012

Данные испытаний:

declare @t table(
Line# int,  Store char(3),  Item char,  OnHand int,  SalesUnits int, DateKey int
)

insert @t values
(1,  '001',  'A',  100,   20, 1),
(2,  '001',  'A',  80 ,   10, 2),
(3,  '001',  'A',  null,  30, 3),
(4,  '001',  'A',  null,   5, 4),
(5,  '001',  'A',  150,   10, 5),
(6,  '001',  'B',  null,   4, 1),
(7,  '001',  'B',  null,   4, 2),
(8,  '001',  'B',  80,    12, 3),
(9,  '001',  'B',  null,  10, 4)

Скрипт для заполнения без использования курсора:

;with a as
(
select Line#,  Store,  Item,  OnHand,  SalesUnits, DateKey, 1 correctdata from @t where DateKey = 1
union all
select t.Line#,  t.Store,  t.Item,  coalesce(t.OnHand, a.onhand - a.salesunits),  t.SalesUnits, t.DateKey, t.OnHand from @t t
join a on a.DateKey = t.datekey - 1 and a.item = t.item and a.store = t.store
)
update t
set OnHand = a.onhand 
from @t t join a on a.line# = t.line#
where a.correctdata is null

Скрипт для заполнения с помощью курсора:

declare @datekey int, @store int, @item char, @Onhand int, 
@calculatedonhand int, @salesunits int, @laststore int, @lastitem char

DECLARE sales_cursor 
CURSOR FOR  
SELECT datekey+1, store, item, OnHand -SalesUnits, salesunits
FROM @t sales  
order by store, item, datekey

OPEN sales_cursor;  
FETCH NEXT FROM sales_cursor  
INTO @datekey, @store, @item, @Onhand, @salesunits

WHILE @@FETCH_STATUS = 0 
BEGIN  
SELECT @calculatedonhand = case when @laststore = @store and @lastitem = @item 
then coalesce(@onhand, @calculatedonhand - @salesunits) else null end
,@laststore = @store, @lastitem = @item

UPDATE s
SET onhand=@calculatedonhand
FROM @t s
WHERE datekey = @datekey and @store = store and @item = item
and onhand is null and @calculatedonhand is not null

FETCH NEXT FROM sales_cursor  
INTO @datekey, @store, @item, @Onhand, @salesunits

END 
CLOSE sales_cursor; 
DEALLOCATE sales_cursor; 

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

...