создание динамического интервала в SQL

У меня есть следующая проблема, которую я хотел бы решить с помощью transact-sql. У меня есть что-то вроде этого

Start | End | Item 1 | 5 | A 3 | 8 | B 

и я хочу создать что-то вроде

 Start | End | Item-Combination 1 | 2 | A 3 | 5 | AB 6 | 8 | B 

Для конкатенации Комбинации Item я уже думал об использовании инструкции FOR XML. Но для того, чтобы создать разные новые интервалы … Я действительно не знаю, как подойти к нему. Есть идеи?

Благодарю.

У меня была очень похожая проблема с некоторыми данными об использовании компьютера. У меня были данные сеанса, указывающие время входа / выхода. Я хотел найти время (час дня в день недели), который наиболее востребован, то есть часы, когда большинство пользователей вошли в систему. Я решил решить проблему на стороне клиента, используя хеш-таблицы. Для каждого сеанса я увеличивал бы ведро в определенном месте, соответствующем дню недели и часу дня для каждого дня / часа, для которого сеанс был активным. После изучения всех сеансов значения хэш-таблицы показывают количество логинов в течение каждого часа для каждого дня недели.

Я думаю, вы могли бы сделать что-то подобное, отслеживая каждый элемент, видимый для каждого начального / конечного значения. Затем вы можете восстановить таблицу, свернув смежные записи, имеющие одну и ту же комбинацию элементов.

И, нет, я не мог придумать способ решить мою проблему с SQL.

Это довольно типичная проблема с поиском дальности с включенной конкатенацией. Не уверен, что следующее соответствует точно, но это отправная точка. (Курсоры обычно лучше избегать, за исключением небольшого набора случаев, когда они быстрее, чем решения на основе набора, поэтому перед тем, как нападающие курсора пойдут на меня, обратите внимание, что я использую курсор здесь специально, потому что это пахнет мне, как удобный для курсора проблема – я обычно избегаю их.)

Поэтому, если я создам такие данные:

 CREATE TABLE [dbo]. [SourceValues] (
     [Start] [int] NOT NULL,
     [End] [int] NOT NULL,
     [Item] [varchar] (100) NOT NULL
 ) ON [PRIMARY]
 ИДТИ

 ALTER TABLE [dbo]. [SourceValues] WITH CHECK ADD CONSTRAINT [End_after_Start] CHECK (([End]> [Start]))
 ИДТИ

 ALTER TABLE [dbo]. [SourceValues] CHECK CONSTRAINT [End_after_Start]
 ИДТИ

 declare @i int;  set @i = 0;
 declare @start int;
 declare @end int;
 объявить @item varchar (100);
 тогда как @i <1000
 начать
     set @start = ABS (CHECKSUM (newid ())% 100) + 1;  - "random" int
     set @end = @start + (ABS (CHECKSUM (newid ())% 10)) + 2;  - больший случайный int
     set @item = char ((ABS (CHECKSUM (newid ()))% 5) + 65);  - случайная буква AE
     print @start;  print @end;  print @item;
     вставлять в значения sourceValues ​​(Start, [End], Item) (@start, @end, @item);
     set @i + = 1;
 конец

Затем я могу рассматривать проблему следующим образом: каждый «Начать», и каждое значение «Конец» представляет собой изменение в коллекции текущих элементов, либо добавив одно, либо удалив один из них в определенное время. В приведенном ниже коде я называю это «событие», что означает «Добавить или удалить». Каждое начало или конец похоже на время, поэтому я использую термин «тик». Если я создаю коллекцию всех событий, упорядоченных по времени события (начало и конец), я могу выполнить итерацию, сохраняя при этом текущую таблицу в таблице памяти всех элементов, которые находятся в игре. Каждый раз, когда значение галочки изменяется, я делаю снимок этой цифры:

 declare @tick int;
 declare @lastTick int;
 объявить @event varchar (100);
 объявить @item varchar (100);
 объявить @concatList varchar (max);
 объявить таблицу @currentItemsList (элемент varchar (100));

 create table #result (Start int, [End] int, Items varchar (max));

 объявлять событияCursor CURSOR FAST_FORWARD для 
     выберите галочку, [событие], элемент из (
         выберите «начать» как «галочку», «Добавить» в качестве [события], элемент из sourceValues ​​как добавление
         союз все 
         выберите [end] как tick, 'Remove' as [event], item from sourceValues ​​как удаляет
     ) как [события] 
     заказывать по тику

 set @lastTick = 1
 open eventsCursor
 выберите следующий из событийCursor в @tick, @event, @item  
 в то время как @@ FETCH_STATUS = 0
 НАЧАТЬ
     if @tick! = @lastTick 
     начать
         set @concatList = ''
         выберите @concatList = @concatlist + case, когда len (@concatlist)> 0 then '-' else '' end + Item 
         из @currentItemsList
         вставить в значения #result (Start, [End], Items) (@lastTick, @tick, @concatList)
     конец

     если @event = 'Добавить' вставить в значения @currentItemsList (Item) (@item);
     else if @event = 'Удалить' delete top (1) из @currentItemsList, где Item = @item;

     set @lastTick = @tick;
     выберите следующий из событийCursor в @tick, @event, @item;
 КОНЕЦ

 close eventsCursor
 deallocate eventsCursor

 выберите * из #result order by start
 drop table #result

Использование курсора для этого специального случая позволяет только один «проход» через данные, например, проблему с текущими итогами. У Ицика Бен-Гана есть отличные примеры этого в его книгах по SQL 2005.

Большое спасибо за все ответы, на данный момент я нашел способ сделать это. SInce Я имею дело с хранилищем данных, и у меня есть измерение времени, я мог бы сделать несколько объединений с измерением времени в стиле «внутреннее объединение DimTime t на t.date между f.start_date и end_date».

Это не очень хорошо с точки зрения производительности, но, похоже, это работает для меня.

Я попробую выполнить onupdatecascade, чтобы посмотреть, какие из них подходят лучше для меня.

Это точно эмулирует и решает указанную проблему:

 -- prepare problem, it can have many rows with overlapping ranges declare @range table ( Item char(1) primary key, [Start] int, [End] int ) insert @range select 'A', 1, 5 insert @range select 'B', 3, 8 -- unroll the ranges into helper table declare @usage table ( Item char(1), Number int ) declare @Start int, @End int, @Item char(1) declare table_cur cursor local forward_only read_only for select [Start], [End], Item from @range open table_cur fetch next from table_cur into @Start, @End, @Item while @@fetch_status = 0 begin with Num(Pos) as -- generate numbers used ( select cast(@Start as int) union all select cast(Pos + 1 as int) from Num where Pos < @End ) insert @usage select @Item, Pos from Num option (maxrecursion 0) -- just in case more than 100 fetch next from table_cur into @Start, @End, @Item end close table_cur deallocate table_cur -- compile overlaps ; with overlaps as ( select Number, ( select Item + '-' from @usage as i where o.Number = i.Number for xml path('') ) as Items from @usage as o group by Number ) select min(Number) as [Start], max(Number) as [End], left(Items, len(Items) - 1) as Items -- beautify from overlaps group by Items 
Interesting Posts

Установить время (0) Тип данных на сервере Sql до NULL

Присоединение к двум таблицам, но не результат

Внешнее ограничение ключа инициируется, даже несмотря на то, что данные существуют

Можно ли использовать CONTAINSTABLE для поиска «word1» в столбце 1 и «word2» в столбце2

SQL-помощь, ограничение количества строк

Как сохранить значение null для числовых значений при использовании BeanUtils.copyProperties?

Мастер импорта SQL Server сбой с непонятным сообщением

Различия в оценке между оператором IF и If, then, else

Выполните хранимую процедуру, передав файл сценария (.sql) в качестве параметра

SQL-подобное выражение не может найти символ полупространства (Zero-Width-Non-Joiner (ZWNJ))

Импорт / экспорт данных базы данных с помощью SQL Server Management Studio

Как хранится индекс varchar?

Развертывание / разбиение строк таблицы на несколько строк

EntityFramework 6 AddOrUpdate не работает с составным или составным первичным ключом

График поворота строки в столбцы коэффициентов? (в MS-SQL)

Давайте будем гением компьютера.