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

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

Хочу понять, как решить такое:

Иванов, Петров, Сидоров собирали металллом некое число месяцев. Период выборки задается вручную. Один, два, пять, семь.

По каждому из них известна дата, когда они что-то принесли и вес.

Как посчитать, сколько кто из них принес в каждом месяце из периода?
3 фев 17, 03:01    [20175742]     Ответить | Цитировать Сообщить модератору
 Re: Как решить задачу без курсора?  [new]
Ennor Tiegael
Member

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

group by eomonth([YourDateColumnName])

Но производительность будет так себе, ибо группировка по вычисляемому полю.
3 фев 17, 03:16    [20175745]     Ответить | Цитировать Сообщить модератору
 Re: Как решить задачу без курсора?  [new]
Dmitry V. Liseev
Member [заблокирован]

Откуда: Санкт-Петербург
Сообщений: 5489
Ennor Tiegael
ElenaTomsk,

group by eomonth([YourDateColumnName])

Но производительность будет так себе, ибо группировка по вычисляемому полю.
Вычисляемое поле можно сделать persisted и построить индекс по нему. Но, это уже детали. Ими надо заниматься, если производительность будет беспокоить.
3 фев 17, 06:24    [20175795]     Ответить | Цитировать Сообщить модератору
 Re: Как решить задачу без курсора?  [new]
Mike_za
Member

Откуда: Москва
Сообщений: 1176
Достаточно индекса по дате. А уж для заданного диапазона сервер месяц посчитает как нибудь не сильно плача.
3 фев 17, 11:27    [20176589]     Ответить | Цитировать Сообщить модератору
 Re: Как решить задачу без курсора?  [new]
WarAnt
Member

Откуда: Питер
Сообщений: 2423
Вы наверное еще и в шахматы в голове умеете играть,

Очередной пятничный треш топик, побежал за попкорном.

если серьезно, как только надоедят рассуждения про вакуум и далекие звезды, выполните пункт 6
3 фев 17, 11:56    [20176750]     Ответить | Цитировать Сообщить модератору
 Re: Как решить задачу без курсора?  [new]
ElenaTomsk
Member

Откуда:
Сообщений: 142
WarAnt
Вы наверное еще и в шахматы в голове умеете играть,

Очередной пятничный треш топик, побежал за попкорном.

если серьезно, как только надоедят рассуждения про вакуум и далекие звезды, выполните пункт 6


В том-то и дело, что привести скрипты, таблицы, это за меня могут сделать. А я бы сама хотела! Но вообще структура таблицы тут три поля, какие там шахматы. Id, DateAction, WeightAction. Спасибо за подсказку, этот момент получился.

Может быть, и такой вопрос подскажете?

Если у меня две таблицы, в одной собственно хранятся данные по весу. Т.е.
create tbl_weight (Id int, WeightAction int, Id_Member Int, DateAction datetime) 

Во второй хранятся данные по участникам соревнований по сбору.
create tbl_member (Id int, Id_Member int, DataRegistration datetime)


И надо посчитать, сколько человек не участвовало на определенную дату. Считать я это пытаюсь как:

select count(*), EOMONTH(DateAction) DateAction  from tbl_weight where Id_Member not in (select Id_Member from tbl_member)
and DateAction between @datestart and @datefinish
group by EOMONTH(DateAction)


И это неправильно. Потому что может быть, он еще и не регистрировался даже на определенную дату. Чувствую, что объясняю криво. :(

Хочу отобрать данные за три месяца. Допустим, за 12-2016, 11-2016, 10-2016. В итоге получаю рекордсет из трех записей.
Но в подсчет за 12-2016 не должны попасть те, у кого дата регистрации меньше 01-12-2016.
В подсчет за 11-2016 не должны попасть те, у кого дата регистрации меньше 01-11-2016.
В подсчет за 10-2016 не должны попасть те, у кого дата регистрации меньше 01-10-2016.

Как это сделать курсором, понятно. А вот без него? Период заранее неизвестен. sql 2010 у меня, если это важно.
3 фев 17, 17:24    [20178458]     Ответить | Цитировать Сообщить модератору
 Re: Как решить задачу без курсора?  [new]
TaPaK
Member

Откуда: Kiev
Сообщений: 6802
ElenaTomsk,

автор
sql 2010 у меня, если это важно.
важно что такого не существует
3 фев 17, 17:26    [20178465]     Ответить | Цитировать Сообщить модератору
 Re: Как решить задачу без курсора?  [new]
ElenaTomsk
Member

Откуда:
Сообщений: 142
TaPaK
ElenaTomsk,

автор
sql 2010 у меня, если это важно.
важно что такого не существует


Ой, правда? 2012, я ошиблась. :( А по существу вопроса можно что-нибудь?
3 фев 17, 17:34    [20178499]     Ответить | Цитировать Сообщить модератору
 Re: Как решить задачу без курсора?  [new]
TaPaK
Member

Откуда: Kiev
Сообщений: 6802
ElenaTomsk,
на вскидку можно так
;WITH Members AS 
(
	SELECT Id_Member 
	FROM tbl_member 
	GROUP BY Id_Member 
),
GameDate AS 
(
	SELECT DateAction
	FROM tbl_weight  
	GROUP BY 
		DateAction
)
SELECT 
	a.MemberId,
	EOMONTH(b.DateAction)
FROM Members		a
CROSS JOIN GameDate	b
WHERE 
	NOT EXISTS 
	(
		SELECT 1
		FROM tbl_weight 
		WHERE 
			Id_Member = a.Id_Member	AND
			EOMONTH(DateAction) = EOMONTH(a.DateAction)
	) AND
	DateAction between @datestart and @datefinish
3 фев 17, 17:38    [20178513]     Ответить | Цитировать Сообщить модератору
 Re: Как решить задачу без курсора?  [new]
TaPaK
Member

Откуда: Kiev
Сообщений: 6802
TaPaK,
судя по всему можно и так, но вижу уже плохо :)
;WITH Members AS 
(
	SELECT Id_Member 
	FROM tbl_member 
	GROUP BY Id_Member 
)
SELECT 
	a.MemberId,
	EOMONTH(ISNULL(c.DateAction,b.DateAction))  as [Action]
FROM 
	Members		a
LEFT JOIN
	tbl_weight	b
ON
	b.Id_Member = a.Id_Member
LEFT JOIN 
	tbl_member	c
ON
	c.Id_Member = a.Id_Member
WHERE 	
	(c.Id IS NULL OR b.Id IS NULL) AND 
	c.DateAction between @datestart and @datefinish
	b.DataRegistration between @datestart and @datefinish
GROUP BY 
	a.MemberId,
	EOMONTH(ISNULL(c.DateAction,b.DateAction))  
3 фев 17, 17:57    [20178583]     Ответить | Цитировать Сообщить модератору
 Re: Как решить задачу без курсора?  [new]
invm
Member

Откуда: Москва
Сообщений: 9836
select
 count(*), EOMONTH(w.DateAction) DateAction
from
 tbl_weight w
where
 w.DateAction between @datestart and @datefinish and
 not exists (select * from tbl_member where Id_Member = w.Id_Member and DateRegistration < dateadd(day, eomonth(w.DateAction, -1), 1))
group by
 EOMONTH(w.DateAction)
3 фев 17, 18:01    [20178594]     Ответить | Цитировать Сообщить модератору
 Re: Как решить задачу без курсора?  [new]
TaPaK
Member

Откуда: Kiev
Сообщений: 6802
invm,

я так понимаю, что мог вообще никогда не участвовать, а только регистрироваться :)
3 фев 17, 18:08    [20178622]     Ответить | Цитировать Сообщить модератору
 Re: Как решить задачу без курсора?  [new]
ElenaTomsk
Member

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

Большое спасибо, ваш вариант выглядит самым красивым. Только вот здесь непонятно:

DATEADD(DAY, EOMONTH(w.DateAction, -1), 1)   


Второй параметр у DATEADD ведь число? А третий дата. Может быть, вот так должно быть?
DATEADD(DAY, 1, EOMONTH(w.DateAction, -1))  


Вот в таком варианте
DATEADD(DAY, 1, EOMONTH(w.DateAction, -1))  
не работает, возвращает одну строку с неверными данными:
1 2016-10-31
3 фев 17, 19:46    [20178963]     Ответить | Цитировать Сообщить модератору
 Re: Как решить задачу без курсора?  [new]
invm
Member

Откуда: Москва
Сообщений: 9836
TaPaK
я так понимаю, что мог вообще никогда не участвовать, а только регистрироваться :)
Возможно :)
ElenaTomsk
Может быть, вот так должно быть?
DATEADD(DAY, 1, EOMONTH(w.DateAction, -1))
Да, так. Это получение первого дня месяца, а не последнего.
ElenaTomsk
не работает, возвращает одну строку с неверными данными
Предлагаете угадать какой запрос и на каких данных вы выполняли?
3 фев 17, 20:47    [20179062]     Ответить | Цитировать Сообщить модератору
 Re: Как решить задачу без курсора?  [new]
ElenaTomsk
Member

Откуда:
Сообщений: 142
invm

ElenaTomsk
не работает, возвращает одну строку с неверными данными

Предлагаете угадать какой запрос и на каких данных вы выполняли?


Конечно, нет. Прилагаю бекап базы данных, там таблицы с оригинальными данными и одна процедура
http://dropmefiles.com/7rKZa - всего двести килобайт.
3 фев 17, 22:56    [20179468]     Ответить | Цитировать Сообщить модератору
 Re: Как решить задачу без курсора?  [new]
ElenaTomsk
Member

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

Предлагаете угадать какой запрос и на каких данных вы выполняли?


Извините, конечно, тут всё правильно, это я уже сама не то посчитала. Большое вам спасибо!
4 фев 17, 16:27    [20180612]     Ответить | Цитировать Сообщить модератору
 Re: Как решить задачу без курсора?  [new]
ElenaTomsk
Member

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

Еще один вопрос есть. Вот этот код

select
count(*), EOMONTH(w.DateAction) DateAction
from  tbl_weight w
where  w.DateAction between @datestart and @datefinish and
not exists (select * from tbl_member where Id_Member = w.Id_Member and DateRegistration < dateadd(day, eomonth(w.DateAction, -1), 1))
group by EOMONTH(w.DateAction)


в случае выборки за 5 месяцев вернет мне, условно, 500 человек, которые не участвовали в соревнованиях. Но это будут те, кто не участвовал вообще. А вот как бы создать рекордсет со списком тех, кто не участвовал в одном месяце, но может, участвовал во втором или в третьем, но не участвовал в четвертом, т.е. помесячно, в виде:

неучаствовало, на дату
79 2016-08-01
150 2016-09-01
250 2016-10-01
315 2016-12-01
450 2017-01-01

Можно, конечно, сделать так:
select
count(*), EOMONTH(w.DateAction) DateAction
from  tbl_weight w
where  w.DateAction between @datestart and @datefinish and
not exists (select * from tbl_member where Id_Member = w.Id_Member and DateRegistration between w.DateAction and dateadd(month, 1, w.DateAction)
group by EOMONTH(w.DateAction)


И так будет выборка помесячно. Повторить это 5 раз, а потом это все сложить через Union. Но как-то криво очень опять. А если 6 месяцев запросят, лезть в код и добавлять запрос еще один, некрасиво и глупо. Но опять не вижу, как это сделать одним запросом.
5 фев 17, 02:06    [20181220]     Ответить | Цитировать Сообщить модератору
 Re: Как решить задачу без курсора?  [new]
iljy
Member

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

Сформулируйте задачу на русском, она будет звучать примерно так: выбрать всех участников, для которых существует месяц, в который нет записей об участии данного участника в соревнованиях. После этого условие практически дословно переводится на скуль.
5 фев 17, 20:27    [20181972]     Ответить | Цитировать Сообщить модератору
 Re: Как решить задачу без курсора?  [new]
ElenaTomsk
Member

Откуда:
Сообщений: 142
iljy
ElenaTomsk,

Сформулируйте задачу на русском, она будет звучать примерно так: выбрать всех участников, для которых существует месяц, в который нет записей об участии данного участника в соревнованиях. После этого условие практически дословно переводится на скуль.


Здравствуйте! Что-то не получается. Попробовла решить через CASE

select count(*)
, Case when Id_member in (select id_member from tbl_weight w where DateRegistration between w.DateAction and dateadd(month, 1, w.DateAction))
, Case when Id_member in (select id_member from tbl_weight w where DateRegistration between w.DateAction and dateadd(month, 2, w.DateAction))
from ...


Оно работает, но это опять некрасиво.
6 фев 17, 15:58    [20185312]     Ответить | Цитировать Сообщить модератору
Все форумы / Microsoft SQL Server Ответить