Гость
Форумы / Microsoft SQL Server [игнор отключен] [закрыт для гостей] / Скалярная функция для расчета конечной даты / 12 сообщений из 12, страница 1 из 1
06.05.2020, 16:44
    #39954691
iLinks
Гость
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Скалярная функция для расчета конечной даты
Написал разными способами скалярную функцию, которая принимает стартовую дату и количество рабочих дней, должна возвращать конечную дату, с учетом праздников, выходных и выходных которые стали рабочими днями.
Учет выходных дней, которые стали рабочими в таблице j_Holidays со статусом 0(там список дат у которых статус 0), учет праздников в таблице j_Holidays со статусом 1 (список дат и статус 1).
[img=]
Алгоритм вроде правильный, но почему то конечная дата выводится неправильно.
К примеру ввожу начальную дату '2020-01-01 00:00:00.000' и количество рабочих дней 1. В таблице праздники идут с 2020-01-01 по 2020-01-03 и с 2020-01-06 по 2020-01-08.
По логике конечная дата должна быть 2020-01-04, но функция выдает почему то 2020-01-09.
Вот один из способов, которые написал:
Код: sql
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
26.
27.
28.
29.
30.
31.
32.
33.
34.
35.
36.
37.
38.
39.
40.
41.
42.
43.
44.
45.
46.
47.
48.
49.
50.
51.
52.
53.
54.
55.
56.
57.
58.
59.
CREATE FUNCTION [OPR].[f_GetLastWorkDay] 
(
	-- Add the parameters for the function here
	@DateStart datetime,	--Стартовая дата
	@CountWorkDay int		--Количество рабочих дней
)
RETURNS datetime
AS
BEGIN
	-- Declare the return variable here
	DECLARE @DateEnd datetime
	DECLARE @n int = 0
	DECLARE @next bit
	DECLARE @ex0 int
	DECLARE @ex1 int
	
	set @DateEnd = @DateStart

	--Циклом добавляем дни
	while (@n<@CountWorkDay)
	BEGIN
		set @n=@n+1
		set @next = 0
		set @DateEnd = DATEADD(day,1,@DateEnd)
		while (@next = 0)
		BEGIN
			IF(DATEPART(weekday, @DateEnd) = 7
			or DATEPART(weekday, @DateEnd) = 1)
			begin
				set @ex0 = (select COUNT(*) from dbo.j_Holidays j_H where  j_H.Date_Holiday in(@DateEnd) AND j_H.Status_Holiday = 0)
				if (@ex0=1)
				begin
					break
				end
				else
				begin
					set @DateEnd = DATEADD(day,1,@DateEnd)
					continue
				end
			end
			ELSE
			begin
				set @ex1 = (select COUNT(*) from dbo.j_Holidays j_H where j_H.Date_Holiday in(@DateEnd) AND j_H.Status_Holiday = 1)
				if (@ex1=1)
				begin
					set @DateEnd = DATEADD(day,1,@DateEnd)
					continue
				end
				else
				begin
					break
				end
			end		
		END
	END
	-- Return the result of the function
	RETURN @DateEnd
END
GO
...
Рейтинг: 0 / 0
06.05.2020, 16:50
    #39954696
Гавриленко Сергей Алексеевич
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Скалярная функция для расчета конечной даты
Написали ужасного монстра - теперь отладкой займитесь.

Еще я бы уточнил, какой день по вашим настройкам сервер считает первым в неделе.
Явной установки, что это понедельник, в коде не наблюдается.
...
Рейтинг: 0 / 0
06.05.2020, 17:03
    #39954701
iLinks
Гость
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Скалярная функция для расчета конечной даты
Гавриленко Сергей Алексеевич,

Код: sql
1.
IF(DATEPART(weekday, @DateEnd) = 7 or DATEPART(weekday, @DateEnd) = 1)


Это условие на субботу и воскресенье
Да вроде не монстра. Могу алгоритм нарисовать, если это как то поможет. А помощь нужна :)
...
Рейтинг: 0 / 0
06.05.2020, 17:09
    #39954705
Гавриленко Сергей Алексеевич
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Скалярная функция для расчета конечной даты
iLinks,

Еще раз. В разных странах неделя начинается в разные дни недели и в разных странах понедельник будет иметь разный порядковый номер. И суббота с воскресеньем тоже.
...
Рейтинг: 0 / 0
06.05.2020, 17:34
    #39954718
iLinks
Гость
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Скалярная функция для расчета конечной даты
Гавриленко Сергей Алексеевич,

...
Рейтинг: 0 / 0
06.05.2020, 17:36
    #39954720
uaggster
Гость
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Скалярная функция для расчета конечной даты
Вообще-то, правильным вариантом будет:
1. Сходить вот сюда: http://data.gov.ru/opendata/resource/8ba5011a-233e-4e01-a1d2-ff5598d0f34f#2/0.0/0.0
2. Скачать и распарсить CSV в нормальную таблицу, лучше вида: Дата - признак рабочий/нерабочий - день недели.
3. Для дней за пределами календаря, например - в будущем или до 1994 года - проставить признак нерабочий день для субботы и воскресенья (например).
4. Считать количество рабочих и нерабочих дней - прямым подсчетом, в интервале дат.
5. Раз в год обновлять табличку.
...
Рейтинг: 0 / 0
06.05.2020, 20:01
    #39954801
iap
iap
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Скалярная функция для расчета конечной даты
iLinks
Гавриленко Сергей Алексеевич,

Выполните в начале SET DATEFIRST 4;
Всё ещё как на вашем рисунке?
...
Рейтинг: 0 / 0
06.05.2020, 20:15
    #39954805
iLinks
Гость
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Скалярная функция для расчета конечной даты
iap,

Я не могу выполнить
Код: sql
1.
SET DATEFIRST

так как это рабочий сервер и там многие процедуры из за этого могут полететь.
Но первый день недели на сервере - это воскресенье.
...
Рейтинг: 0 / 0
06.05.2020, 21:04
    #39954815
alexeyvg
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Скалярная функция для расчета конечной даты
iLinks
Да вроде не монстра. Могу алгоритм нарисовать, если это как то поможет. А помощь нужна :)
Ага, одно это
Код: sql
1.
2.
set @ex1 = (select COUNT(*) from #j_Holidays j_H where j_H.Date_Holiday in(@DateEnd) AND j_H.Status_Holiday = 1)
if (@ex1=1)

Вместо if exists чего стоит

iLinks
Могу алгоритм нарисовать, если это как то поможет. А помощь нужна :)
Что в таблице Date_Holiday, и что означает поле Status_Holiday?

Если не хотите сделать нормально, как написал uaggster, то хотя бы сделайте из вашего монстра один запрос, по типу
Код: sql
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
select @DateEnd = dt
from (
	select top (@CountWorkDay) dt, row_number() over(order by dt desc) as N
	from (
		select dateadd(dd, N, @DateStart) as dt
		from (
			select top (@CountWorkDay*2 + 30) (row_number() over(order by getdate())) - 1 as N from sysobjects o1 cross join sysobjects o2
		) t
	) t
	where DATEPART(weekday, dt) not in (1,7)
) t
where N = 1
...
Рейтинг: 0 / 0
06.05.2020, 21:08
    #39954817
invm
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Скалярная функция для расчета конечной даты
iLinks,

Ваша задача решается одним запросом и без заумных циклов.
Код: sql
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
declare @DateStart date = getdate(), @DaysCount int = 23;

with t as
(
 select
  @DateStart as d, case when (datepart(dw, @DateStart) + @@datefirst - 2) % 7 + 1 in (6, 7) then 0 else 1 end as cnt
 where
  @DaysCount > 0

 union all

 select
  a.d, t.cnt + case when (datepart(dw, a.d) + @@datefirst - 2) % 7 + 1 in (6, 7) then 0 else 1 end
 from
  t cross apply
  (select dateadd(day, 1, t.d)) a(d)
 where
  t.cnt < @DaysCount
)
select
 max(d), datediff(day, @DateStart, max(d))
from
 t
option
 (maxrecursion 0);


Таблицу праздников добавите самостоятельно.

И вместо скалярной функции сделать инлайновую
...
Рейтинг: 0 / 0
06.05.2020, 21:21
    #39954822
iap
iap
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Скалярная функция для расчета конечной даты
iLinks
iap,

Я не могу выполнить
Код: sql
1.
SET DATEFIRST


так как это рабочий сервер и там многие процедуры из за этого могут полететь.
Но первый день недели на сервере - это воскресенье.
SET действует только в текущей сессии.
Никто, кроме вас, не заметит.
...
Рейтинг: 0 / 0
07.05.2020, 04:50
    #39954866
Ennor Tiegael
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Скалярная функция для расчета конечной даты
iap,

Еще лучше будет так:
Код: sql
1.
set language russian;
...
Рейтинг: 0 / 0
Форумы / Microsoft SQL Server [игнор отключен] [закрыт для гостей] / Скалярная функция для расчета конечной даты / 12 сообщений из 12, страница 1 из 1
Целевая тема:
Создать новую тему:
Автор:
Найденые пользователи ...
Разблокировать пользователей ...
Читали форум (0):
Пользователи онлайн (0):
x
x
Закрыть


Просмотр
0 / 0
Close
Debug Console [Select Text]