powered by simpleCommunicator - 2.0.28     © 2024 Programmizd 02
Map
Форумы / Microsoft SQL Server [игнор отключен] [закрыт для гостей] / Подскажите как сделать отбор
10 сообщений из 10, страница 1 из 1
Подскажите как сделать отбор
    #40133412
alexandrDr87
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
Есть таблица со следующими данными. Время открытия и закрытия может быть как в одном месяце, так и в разных.


INCIDENT | OPEN_TIME | CLOSE_TIME
===============================================
IN123456 | 2022-01-03 08:41:22.000 | 2022-03-10 09:40:27.000


Мне необходимо отобрать такие записи в другую таблицу, где они бы разделились следующим образом:

INCIDENT | OPEN_TIME | CLOSE_TIME
===============================================
IN123456 | 2022-01-03 08:41:22.000 | 2022-01-31 23:59:00.000

IN123456 | 2022-02-01 00:00:00.000 | 2022-02-28 23:59:00.000

IN123456 | 2022-03-01 00:00:00.000 | 2022-03-10 09:40:27.000

То есть чтоб первоначальная запись разбилась на промежутки по месяцам и последний промежуток заканчивался как раз датой CLOSE_TIME первоначальной таблицы
...
Рейтинг: 0 / 0
Подскажите как сделать отбор
    #40133420
Владислав Колосов
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
alexandrDr87,

составьте календарь последних дней месяца, выберите все сочетания таблиц при условии, что дата календаря попадает между началом и концом.
...
Рейтинг: 0 / 0
Подскажите как сделать отбор
    #40133615
alexandrDr87
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
Спасибо всем кто обратил внимание на тему.
У меня все же получилось это сделать. Надеюсь на конструктивную критику и возможно подсказки по оптимизации. На данный момент как по мне работает достаточно сносно. 10 000 строк обрабатывает 18 секунд.

Код: 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.
CREATE PROCEDURE [dbo].[spLoad]
AS
BEGIN
  SET NOCOUNT ON;

  TRUNCATE TABLE tAppeals;

  DECLARE @appeal_id nvarchar(100);
  DECLARE @open_time datetime;
  DECLARE @close_time datetime;

  DECLARE appeals_cursor CURSOR FOR
    SELECT INCIDENT_ID, OPEN_TIME, CLOSE_TIME
    FROM OPENQUERY([server], 'SELECT [INCIDENT_ID], [OPEN_TIME], [CLOSE_TIME]
                                                   FROM [base].[dbo].[table]
                                 ')
 
  OPEN appeals_cursor

  FETCH NEXT FROM appeals_cursor INTO @appeal_id, @open_time, @close_time

  WHILE @@FETCH_STATUS = 0
  BEGIN
       DECLARE @new_open_time datetime;
       DECLARE @new_close_time datetime;
       DECLARE @final_close_time datetime;

       SET @final_close_time = @close_time;
       SET @new_open_time = @open_time;

       WHILE DATEPART(month, @new_open_time) < DATEPART(MONTH, @close_time)
       BEGIN
           SET @new_close_time = CONCAT(CONVERT(nvarchar(10), CONVERT(date, EOMONTH(@open_time))), ' ' +  '23:59:59.000')

           INSERT INTO tAppeals (appeal_id, open_time, close_time) VALUES(@appeal_id, @open_time, @new_close_time)

           SET @new_open_time = DATEADD(MONTH, 1 + DATEDIFF(MONTH, 0, @open_time), 0);
            SET @open_time = @new_open_time;
       END;

       IF DATEPART(month, @new_open_time) = DATEPART(MONTH, @close_time)
           INSERT INTO tAppeals (appeal_id, open_time, close_time) VALUES(@appeal_id, @open_time, @final_close_time)

       FETCH NEXT FROM appeals_cursor INTO @appeal_id, @open_time, @close_time
  END
CLOSE appeals_cursor
END;
GO
...
Рейтинг: 0 / 0
Подскажите как сделать отбор
    #40133625
Фотография alexeyvg
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
alexandrDr87
У меня все же получилось это сделать
На что только люди не идут, что бы не делать таблицу-календарь :-(
...
Рейтинг: 0 / 0
Подскажите как сделать отбор
    #40133634
alexandrDr87
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
alexeyvg
alexandrDr87
У меня все же получилось это сделать
На что только люди не идут, что бы не делать таблицу-календарь :-(


Покажите решение с календарем, я не понимаю что вы имеете ввиду
...
Рейтинг: 0 / 0
Подскажите как сделать отбор
    #40133635
godsql
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
Код: sql
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
declaRE @T TABLE
(
INCIDENT VARCHAR(20),
OPEN_TIME DATETIME ,
CLOSE_TIME  DATETIME 
)

INSERT INTO @T  (INCIDENT , OPEN_TIME , CLOSE_TIME)
VALUES ('IN123456', '2022-01-03T08:41:22.000','2022-05-10T09:40:27.000')
INSERT INTO @T  (INCIDENT , OPEN_TIME , CLOSE_TIME)
VALUES ('IN123987', '2022-04-15T08:41:22.000','2022-08-01T09:40:27.000')


SELECT T.*, T2.NUM, 
	IIF(T2.NUM=1, T.OPEN_TIME, (DATEADD(day,1,EOMONTH(dateadd(MM, T2.NUM-2,T.OPEN_TIME))))) AS OPEN_TIME1,
	IIF(T2.NUM=DATEDIFF(MM,T.OPEN_TIME, T.CLOSE_TIME) +1, T.CLOSE_TIME
			, EOMONTH(dateadd(MM, T2.NUM-1,T.OPEN_TIME))) AS CLOSE_TIME1
	 FROM @T T
CROSS APPLY ( 
	SELECT TOP (DATEDIFF(MM,T.OPEN_TIME, T.CLOSE_TIME) +1) 
	ROW_NUMBER() OVER (ORDER BY 1/0) AS NUM
	FROM SYS.all_objects) T2
...
Рейтинг: 0 / 0
Подскажите как сделать отбор
    #40133672
PizzaPizza
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Когда вам кажется что в РБД вам надо сделать курсор, вам надо либо пересмотреть хранение ваших данных либо почитать функционал вашей базы данных.

alexandrDr8710 000 строк обрабатывает 18 секунд.
И это только начало. Курсор вам и не такое выделает
...
Рейтинг: 0 / 0
Подскажите как сделать отбор
    #40133677
LexusR
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Код: 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.
declaRE @T TABLE
(
INCIDENT VARCHAR(20),
OPEN_TIME DATETIME ,
CLOSE_TIME  DATETIME 
)

INSERT INTO @T  (INCIDENT , OPEN_TIME , CLOSE_TIME)
VALUES ('IN123456', '2022-01-03T08:41:22.000','2022-05-10T09:40:27.000')
INSERT INTO @T  (INCIDENT , OPEN_TIME , CLOSE_TIME)
VALUES ('IN123987', '2022-04-15T08:41:22.000','2022-08-01T09:40:27.000')



;WITH Result AS (SELECT INCIDENT , OPEN_TIME , CLOSE_TIME, 0 as [Shift]
,OPEN_TIME as OPEN_TIME1
,IIF(EOMONTH(OPEN_TIME,0)< CLOSE_TIME,EOMONTH(OPEN_TIME,0),CLOSE_TIME) AS CLOSE_TIME1
FROM @T
UNION ALL
SELECT r.INCIDENT , r.OPEN_TIME , r.CLOSE_TIME,r.[Shift]+1 as [Shift]
,DATEADD(dd,1,r.CLOSE_TIME1) as OPEN_TIME1
,IIF(EOMONTH(r.OPEN_TIME,r.[Shift]+1)< r.CLOSE_TIME,EOMONTH(r.OPEN_TIME,r.[Shift]+1),r.CLOSE_TIME) AS CLOSE_TIME1
FROM @T t
JOIN Result r on r.INCIDENT = t.INCIDENT and r.CLOSE_TIME1 < r.CLOSE_TIME
)
SELECT INCIDENT,OPEN_TIME,CLOSE_TIME,OPEN_TIME1,CLOSE_TIME1
FROM Result ORDER BY INCIDENT , OPEN_TIME1

alexandrDr87,
...
Рейтинг: 0 / 0
Подскажите как сделать отбор
    #40133732
Фотография alexeyvg
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
alexandrDr87
alexeyvg
пропущено...
На что только люди не идут, что бы не делать таблицу-календарь :-(


Покажите решение с календарем, я не понимаю что вы имеете ввиду
Вам выше написали:
Владислав Колосов
составьте календарь последних дней месяца, выберите все сочетания таблиц при условии, что дата календаря попадает между началом и концом.
Тут же очевидно всё.
Есть календарь, делаете к нему джойн вашей таблицы
В результате для одной записи из вашей таблицы получается одна запись на каждую запись в календаре, с которой она джойнится по условию соединения.

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

Пример кода от godsql - это тоже по сути решения с календарём, только он формируется на лету, прямо в запросе.
А код от LexusR - это как бы курсор, только в виде CTE

А вот пример с календарём в чистом виде:
Код: 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.
declare @Calendar TABLE
(
	num int,
	start_time datetime,
	next_time datetime,
	close_time datetime
)
insert @Calendar
select num, dateadd(mm, num - 1, '20200101'), dateadd(mm, num, '20200101'), dateadd(mi, -1, dateadd(mm, num, '20200101'))
from (SELECT ROW_NUMBER() OVER (ORDER BY 1/0) AS NUM FROM SYS.all_objects) n

declaRE @T TABLE
(
	INCIDENT VARCHAR(20),
	OPEN_TIME DATETIME ,
	CLOSE_TIME  DATETIME 
)

INSERT INTO @T  (INCIDENT , OPEN_TIME , CLOSE_TIME)
VALUES ('IN123456', '2022-01-03T08:41:22.000','2022-05-10T09:40:27.000')
INSERT INTO @T  (INCIDENT , OPEN_TIME , CLOSE_TIME)
VALUES ('IN123987', '2022-04-15T08:41:22.000','2022-08-01T09:40:27.000')


select t.INCIDENT, case when t.OPEN_TIME > c.start_time then t.OPEN_TIME else c.start_time end as OPEN_TIME, case when t.CLOSE_TIME < c.next_time then t.CLOSE_TIME else c.close_time end as CLOSE_TIME
from @T t
	join @Calendar as c on c.start_time < t.CLOSE_TIME and c.next_time > t.OPEN_TIME
order by INCIDENT, OPEN_TIME
...
Рейтинг: 0 / 0
Подскажите как сделать отбор
    #40134121
ValK412
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
alexandrDr87,
если попробуете такой вариант с рекурсией, будет интересно сравнить время выполнения с текущей Вашей реализацией
Код: 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.
declaRE @T TABLE(INCIDENT VARCHAR(20),OPEN_TIME DATETIME ,CLOSE_TIME  DATETIME )

INSERT INTO @T  (INCIDENT , OPEN_TIME , CLOSE_TIME) VALUES 
('IN123450', '2020-01-01T08:41:22.000','2020-03-01T09:40:27.000') -- високосный
,('IN123456', '2022-01-03T08:41:22.000','2022-05-10T09:40:27.000')
,('IN123987', '2022-04-15T08:41:22.000','2022-08-01T09:40:27.000')  --начало месяца в конце
,('IN123501', '2022-01-03T08:41:22.000','2022-01-10T09:40:27.000');

with tm as (
select incident,1 as num, open_time as ot , close_time ct 
	,dateadd(d,-datepart(d,open_time)+1,open_time) as bMon
	from @t as t
union all
	select tm.incident, num+1, tm.ot,tm.ct
	,dateadd(m,1,tm.bMon)
	from tm inner join @t as t on  t.INCIDENT=tm.incident
	where dateadd(m,1,tm.bMon)<=ct
)

select INCIDENT,num,
	case when (ot>bMon) then ot else cast(bMon as date) end as open_timeN,
	case when (datediff(m,bMon,ct)=0) then  ct 
	  else -- на 2 миллисекунды меньше начала следующего дня (месяца)
		dateadd(ms,-2,cast(dateadd(m,1,cast(bMon as date)) as datetime)) 
	end as close_timeN
	from tm
order by INCIDENT,num
...
Рейтинг: 0 / 0
10 сообщений из 10, страница 1 из 1
Форумы / Microsoft SQL Server [игнор отключен] [закрыт для гостей] / Подскажите как сделать отбор
Целевая тема:
Создать новую тему:
Автор:
Закрыть
Цитировать
Найденые пользователи ...
Разблокировать пользователей ...
Читали форум (0):
Пользователи онлайн (0):
x
x
Закрыть


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