Добро пожаловать в форум, Guest  >>   Войти | Регистрация | Поиск | Правила | В избранное | Подписаться
Все форумы / Microsoft SQL Server Новый топик    Ответить
 Задача для курсора  [new]
SQLNooba
Guest
Здавствуйте гуру SQL!

Помогите решить задачу:
Есть типы документов от 1 до 7 (DocType)
Тип документа 2 отнимает Demand, все остальные типы прибавляют.
Результат действия для каждой строки нужно апдейтить в Proj в этой же таблице.

Столбец "действие" показывает что происходит с каждой записью для наглядности (в базе этот столбец не нужен)

Все действия происходят по порядку начиная с 1ой строки (строки будут предварительно отсортированны по DocType, DocDate)

В итоге мы получаем проапдейченный столбец Proj для таблицы

DocType Demand Proj действие
1 10 10 +10
1 0 10 +0
2 5 5 -5
2 5 0 -5
2 5 -5 -5
3 3 -2 +3
3 1 -1 +1
4 5 4 +5
5 5 9 +5
6 0 9 +0
7 0 9 +0


Знаю что нужно это делать с помощью курсора, помогите пожалуйста составить примерный запросю Заранее Спасибо!
23 июл 12, 10:37    [12900765]     Ответить | Цитировать Сообщить модератору
 Re: Задача для курсора  [new]
SomewhereSomehow
Member

Откуда: Moscow
Сообщений: 2480
Блог
SQLNooba,

можно и без курсора, как-нибудь так
declare @t table(DocDate datetime primary key, DocType int, Demand int);
insert @t values 
('20120101', 1,10),('20120102', 1,0),('20120103', 2,5),
('20120104', 2,5),('20120105', 2,5),('20120106', 3,3),('20120107', 3,1),
('20120108', 4,5),('20120109', 5,5),('20120110', 6,0),('20120111', 7,0)

select
	t1.DocType,
	t1.Demand,
	s.Proj
from 
	@t t1
	cross apply (select sum(case when DocType = 2 then Demand*-1 else Demand end) from @t t2 where t2.DocDate <= t1.DocDate and t2.DocType<=t1.DocType) s(Proj)

особо не проверял
23 июл 12, 10:48    [12900840]     Ответить | Цитировать Сообщить модератору
 Re: Задача для курсора  [new]
SQLNooba
Guest
SomewhereSomehow, спасибо.

Но надо по порядку бежать по строчкам начиная с верхней и до последней выполняя действия, результат расчета Proj для каждой строки важен
23 июл 12, 11:17    [12901039]     Ответить | Цитировать Сообщить модератору
 Re: Задача для курсора  [new]
SomewhereSomehow
Member

Откуда: Moscow
Сообщений: 2480
Блог
SQLNooba,

В описанной задаче результат для колонки Proj может быть получен для любой строки не основываясь на вычислении результата для предыдущей. Вот если бы у вас результат последующей по условию зависел от предыдущей, по этому из предложенных условий я не понимаю, зачем нужно именно "бежать" построчно.
Ну если прям именно через курсор хотите апдейтить и считать, то можно что-то вроде этого сделать:
+
declare @t table(DocDate datetime primary key, DocType int, Demand int, Proj int);
insert @t(DocDate, DocType,Demand) values 
('20120101', 1,10),('20120102', 1,0),('20120103', 2,5),
('20120104', 2,5),('20120105', 2,5),('20120106', 3,3),('20120107', 3,1),
('20120108', 4,5),('20120109', 5,5),('20120110', 6,0),('20120111', 7,0);

declare @dt int = null, @d int = 0, @p int = 0;
declare cur cursor local forward_only for 
select
	DocType,
	Demand
from 
	@t t1
order by
	DocDate,
	DocType
for update of Proj;

open cur;
fetch next from cur into @dt, @d;

while @@fetch_status = 0 begin
	
	set @p += (case when @dt = 2 then -1 else 1 end)*isnull(@d,0);
	update @t set Proj = @p where current of cur;
	
	fetch next from cur into @dt, @d;
	
end;

close cur;
deallocate cur;

select * from @t
23 июл 12, 12:43    [12901842]     Ответить | Цитировать Сообщить модератору
 Re: Задача для курсора  [new]
Mnior
Member

Откуда: Кишинёв
Сообщений: 6724
Версия сервера какая?
PRINT @@Version
23 июл 12, 15:08    [12903025]     Ответить | Цитировать Сообщить модератору
 Re: Задача для курсора  [new]
Yuriy Petrov
Member

Откуда:
Сообщений: 91
SQLNooba
Здавствуйте гуру SQL!

Помогите решить задачу:
Есть типы документов от 1 до 7 (DocType)
Тип документа 2 отнимает Demand, все остальные типы прибавляют.
Результат действия для каждой строки нужно апдейтить в Proj в этой же таблице.

Столбец "действие" показывает что происходит с каждой записью для наглядности (в базе этот столбец не нужен)

Все действия происходят по порядку начиная с 1ой строки (строки будут предварительно отсортированны по DocType, DocDate)

В итоге мы получаем проапдейченный столбец Proj для таблицы

DocType Demand Proj действие
1 10 10 +10
1 0 10 +0
2 5 5 -5
2 5 0 -5
2 5 -5 -5
3 3 -2 +3
3 1 -1 +1
4 5 4 +5
5 5 9 +5
6 0 9 +0
7 0 9 +0


Знаю что нужно это делать с помощью курсора, помогите пожалуйста составить примерный запросю Заранее Спасибо!

Решение без курсора:
declare @data table (
	DocType int,
	Demand int,
	Proj int,
	DocDate datetime
);

insert into @data
select *
  from (values (1,10,0, GETDATE ()),
			   (1,0,0, GETDATE ()+1),
			   (2,5,0, GETDATE ()),
			   (2,5,0, GETDATE ()+1),
			   (2,5,0, GETDATE ()+2),
			   (3,3,0, GETDATE ()),
			   (3,1,0, GETDATE ()+1),
			   (4,5,0, GETDATE ()),
			   (5,5,0, GETDATE ()),
			   (6,0,0, GETDATE ()),
			   (7,0,0, GETDATE ())
	   )
	   data (c1, c2, c3, c4);

with
cteData
as (
	select *,
			case when DocType = 2 then -1 else 1 end as [Sign],
			case when DocType = 2 then '-' else '+' end + cast(Demand as varchar) as [Act]
	from @data
)
select d1.DocType,
       d1.Demand,
       (select sum (d2.Demand * d2.[Sign])
          from cteData d2
         where d2.DocType < d1.DocType
            or (d2.DocType = d1.DocType and d2.DocDate <= d1.DocDate)
       ),
       d1.Act
  from cteData d1;

Правда на больших объемах, и если сервер не 2012й, курсор может работать быстрее.
В 2012м расширенные опции оконных функций избавляют от суммирующего подзапроса, должны работать быстрее курсора.
23 июл 12, 19:14    [12904887]     Ответить | Цитировать Сообщить модератору
 Re: Задача для курсора  [new]
SQLNooba
Guest
SomewhereSomehow,
Вы правы, Ваш 1ый способ верно работает как и 2ой

Вся эта таблица (ниже пример) для обработки состоит из материалов (Mat) у которых есть документы Doctype, дата докумена DocDate и Demand на основании которго нужно вычеслить Proj по алгоритму из 1го поста
для расчета нам нужна сортировка в последовательности: Mat, Doctype, DocDate.

Я сначала думал взять курсор и пробежать циклом по каждому Mat. Но судя по Вашему cross apply видимо есть и другие эффективные способы.

Yuriy Petrov, спасибо за ваш вариант, таблица состоит из ~500 000 записей подобных ниже


Mat DocDate DocType Demand Proj
100001 1 10
100001 1 0
100001 2 5
100001 2 5
100001 2 5
100001 3 3
100001 3 1
100001 4 5
100001 5 5
100001 6 0
100001 7 0
100005 5 12
100005 1 3
100005 2 5
100005 2 6
100005 3 0
100005 7 0
100005 1 0
100338 3 4
100338 2 2
100338 7 1
100338 7 2
100338 7 0


Mnior,
Microsoft SQL Server 2008 (RTM) - 10.0.1600.22 (X64)
Jul 9 2008 14:17:44
Enterprise Edition (64-bit) on Windows NT 6.0 <X64> (Build 6002: Service Pack 2)
24 июл 12, 10:02    [12906538]     Ответить | Цитировать Сообщить модератору
Все форумы / Microsoft SQL Server Ответить