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

Откуда:
Сообщений: 1480
Нужно для каждой даты факта получить количество - сколько дней прошло с момента последней операции.
Задача проста, возможно и повторюсь, но что-то никак не получается.


select

Дата,
ДатаОперации,
Юзер,
row_number() over(partition by Юзер order by Дата,ДатаОперации) -1 as [Прошло дней с последней операции]

FROM [Факты]

К сообщению приложен файл. Размер - 66Kb
25 окт 13, 10:20    [15030016]     Ответить | Цитировать Сообщить модератору
 Re: Как сделать без курсора?  [new]
Santa89
Member

Откуда:
Сообщений: 1480
Также можно пойти другим путём.
Заполнить поле ДатаОперации датой последней операции из фактов по операциям,
и в первой табличке в поле ПрошлоДнейСПоследнейОперации применить простой DateDiff.

как обновить поле ДатаОперации для каждого юзера, чтобы в нём не было пустых значений?

К сообщению приложен файл. Размер - 13Kb
25 окт 13, 10:43    [15030211]     Ответить | Цитировать Сообщить модератору
 Re: Как сделать без курсора?  [new]
Ennor Tiegael
Member

Откуда:
Сообщений: 3274
select c.date, ca.OperationDate
from dbo.Calendar c
  cross apply (select max(op.Date) as [OperationDate] from dbo.Operations op where op.Date <= c.Date) ca
25 окт 13, 10:50    [15030262]     Ответить | Цитировать Сообщить модератору
 Re: Как сделать без курсора?  [new]
Santa89
Member

Откуда:
Сообщений: 1480
Ennor Tiegael,

дороговато будет..
думаю пойти по второму пути. заполнить поле ДатаОперации - датой последней операции для каждого юзера на дату.
подскажите как?
25 окт 13, 11:04    [15030366]     Ответить | Цитировать Сообщить модератору
 Re: Как сделать без курсора?  [new]
Ennor Tiegael
Member

Откуда:
Сообщений: 3274
Santa89,

Мой пример именно это и делает. Можете вместо max() взять top (1) ... order by ... desc, но вроде особой разницы нет.
25 окт 13, 11:07    [15030395]     Ответить | Цитировать Сообщить модератору
 Re: Как сделать без курсора?  [new]
Santa89
Member

Откуда:
Сообщений: 1480
Ennor Tiegael,

для следующего юзера с ИД=2 даты стали повторятся.
как сделать связь по юзеру для таблиц Операции и Факты в вашем запросе?
25 окт 13, 11:19    [15030488]     Ответить | Цитировать Сообщить модератору
 Re: Как сделать без курсора?  [new]
Santa89
Member

Откуда:
Сообщений: 1480
Ennor Tiegael,

спасибо, разобрался.
но мне кажется что cross apply умрет на больших данных...
25 окт 13, 11:23    [15030508]     Ответить | Цитировать Сообщить модератору
 Re: Как сделать без курсора?  [new]
Ivan Durak
Member

Откуда: Minsk!!!
Сообщений: 3618
Santa89
Также можно пойти другим путём.
Заполнить поле ДатаОперации датой последней операции из фактов по операциям,
и в первой табличке в поле ПрошлоДнейСПоследнейОперации применить простой DateDiff.

так и сделай. Иначе каждый раз с сортингом - помрет все
25 окт 13, 11:25    [15030526]     Ответить | Цитировать Сообщить модератору
 Re: Как сделать без курсора?  [new]
Alex Choo
Member

Откуда: г. Раменское
Сообщений: 44
if object_id('tempdb..#t') is not null drop table #t
create table #t (
	usr int NULL, -- user
	dt datetime NULL, -- date
	dto datetime NULL -- date oper
)
insert into #t (usr, dt, dto) values(1, convert(datetime, '20130101'), convert(datetime, '20130101'))
insert into #t (usr, dt, dto) values(1, convert(datetime, '20130102'), NULL)
insert into #t (usr, dt, dto) values(1, convert(datetime, '20130103'), NULL)
insert into #t (usr, dt, dto) values(1, convert(datetime, '20130104'), NULL)
insert into #t (usr, dt, dto) values(1, convert(datetime, '20130105'), convert(datetime, '20130105'))
insert into #t (usr, dt, dto) values(1, convert(datetime, '20130106'), NULL)
insert into #t (usr, dt, dto) values(1, convert(datetime, '20130107'), NULL)
insert into #t (usr, dt, dto) values(1, convert(datetime, '20130108'), NULL)
insert into #t (usr, dt, dto) values(1, convert(datetime, '20130109'), convert(datetime, '20130109'))
insert into #t (usr, dt, dto) values(1, convert(datetime, '20130110'), NULL)

-- begin 
;
WITH max_dto AS (
	SELECT usr,
				dto
		FROM #t
),
date_last_oper AS (
	SELECT t.usr,
				t.dt,
				max(md.dto) as dto
	FROM #t t
	INNER JOIN max_dto md ON md.usr = t.usr
												AND md.dto <= t.dt
	GROUP BY t.usr, t.dt
)
SELECT d.usr, d.dt, t.dto, 
			ROW_NUMBER() OVER(PARTITION BY d.usr, d.dto ORDER BY d.dt) - 1 days_after_last_oper
	FROM date_last_oper	d
	INNER JOIN #t t ON t.usr = d.usr
									AND t.dt = d.dt		
	ORDER BY d.usr, d.dt


usr dt dto days_after_last_oper
1 2013-01-01 00:00:00.000 2013-01-01 00:00:00.000 0
1 2013-01-02 00:00:00.000 NULL 1
1 2013-01-03 00:00:00.000 NULL 2
1 2013-01-04 00:00:00.000 NULL 3
1 2013-01-05 00:00:00.000 2013-01-05 00:00:00.000 0
1 2013-01-06 00:00:00.000 NULL 1
1 2013-01-07 00:00:00.000 NULL 2
1 2013-01-08 00:00:00.000 NULL 3
1 2013-01-09 00:00:00.000 2013-01-09 00:00:00.000 0
1 2013-01-10 00:00:00.000 NULL 1
25 окт 13, 12:07    [15030823]     Ответить | Цитировать Сообщить модератору
 Re: Как сделать без курсора?  [new]
Alex Choo
Member

Откуда: г. Раменское
Сообщений: 44
Что-то табуляция поползла... Извиняйте.
25 окт 13, 12:09    [15030842]     Ответить | Цитировать Сообщить модератору
 Re: Как сделать без курсора?  [new]
Добрый Э - Эх
Guest
Santa89,

если версия сервера позволяет, то накопительным итогом разбить данные на группы, далее тем же row_number-ом с кляузой PARTITION перенумеровать строки внутри групп.
25 окт 13, 12:12    [15030873]     Ответить | Цитировать Сообщить модератору
 Re: Как сделать без курсора?  [new]
Добрый Э - Эх
Guest
Как вариант реализации...
25 окт 13, 12:19    [15030956]     Ответить | Цитировать Сообщить модератору
Все форумы / Microsoft SQL Server Ответить