Добро пожаловать в форум, Guest  >>   Войти | Регистрация | Поиск | Правила | В избранное | Подписаться
Все форумы / Microsoft SQL Server Новый топик    Ответить
 Получить следующее последовательное число, не дающее коллизий  [new]
scoreZ
Guest
Коллеги, не подскажете, как решить задачку: в двух таблицах есть элементы, коллизий с которыми быть не должно. Элементы не полностью совпадают, имеется некая база, начиная с которой идёт инкремент. Но дело в том, что доступ к редактированию таблиц (добавление и удаление записей) есть у пользователя и поэтому полагаться на то, что коллизии не будет я не могу - вдруг пользователю захочется создать элементы, с которыми она произойдёт. Такой вот пример:
declare @T1 table (M varchar(10)); -- интересующие нас элементы с коллизией имеют базу 100000 (но не обязательно должны иметь формат 1ххххх, после 199999 будет 200000, 200001 и т.д.)
declare @T2 table (N varchar(10)); -- полностью аналогично предыдущему, но база 200000
declare @Z table (X int); -- в эту таблицу будут записываться последовательные числа, не имеющие коллизий с базовыми значениями таблиц @T1 и @T2

insert into @T1 values ('100005');
insert into @T2 values ('200003');
insert into @T2 values ('200004');
insert into @T2 values ('200006');
insert into @T1 values ('100009');
insert into @Z values (2);

-- следующим числом @Z.X должно быть 7
-- т.к. 2 уже было, 3 и 4 находятся в @T2, 5 в @T1, 6 в @T2
-- но не 10 - так, конечно, было бы проще, но нужно вклиниться между занятыми 6 и 9

insert into @Z values ((select isnull(max(X),0)+1 from @Z /*where ??? @T1.M-100000 ??? @T2.N-200000 ??? */));
select * from @Z;

SQL Server 2008 R2. Функцию очень не хотелось бы использовать, лучше всего один запрос.
У меня была идея заджоинить выборки с таблиц @T1 b @T2 и автоинкремент, получить первое значение где M и N будут null... Но я не знаю, как сюда привязать автоинкремент. По номеру строки как-то не получится - у меня же должны быть "дыры", а если в обоих таблицах нет нужного индекса - и строки не будет... Чувствую, что должно быть правильное решение, но я его как-то не вижу...
8 авг 17, 18:57    [20709289]     Ответить | Цитировать Сообщить модератору
 Re: Получить следующее последовательное число, не дающее коллизий  [new]
Гавриленко Сергей Алексеевич
Member

Откуда: Moscow
Сообщений: 36905
Завести таблицу с числавми и уже из нее "выдавать" значения в @T1/@T2/.../@TN (с соттветствущей отметкой, куда "выдано")

Сообщение было отредактировано: 8 авг 17, 19:02
8 авг 17, 19:02    [20709296]     Ответить | Цитировать Сообщить модератору
 Re: Получить следующее последовательное число, не дающее коллизий  [new]
scoreZ
Guest
Гавриленко Сергей Алексеевич, так собственно таблицы @Z для этого и служит. Чтобы выдавать значения для @T1 и @T2. Другое дело что в последние таблицы пишу не только я, но и пользователи. И они как раз могут случайно вставить запись, которая приведёт к коллизии.
8 авг 17, 19:24    [20709325]     Ответить | Цитировать Сообщить модератору
 Re: Получить следующее последовательное число, не дающее коллизий  [new]
Remind
Member

Откуда: UK
Сообщений: 523
scoreZ,

Что-то типа такого?

declare @max int; 
select @max = max(X) from @z

;with cte(Y) as 
(
  select @max
union
  select M-100000 from @T1 where M > @max + 100000
union
  select N-200000 from @T2 where N > @max + 200000
),
rn as
(
  select *, rn = row_number() over (order by Y) + @max - 1 from cte
)
select isnull(min(rn), (select max(Y) from cte)) from rn where rn <> Y
8 авг 17, 20:39    [20709433]     Ответить | Цитировать Сообщить модератору
 Re: Получить следующее последовательное число, не дающее коллизий  [new]
Remind
Member

Откуда: UK
Сообщений: 523
select max(Y) + 1 from cte
конечно же
8 авг 17, 20:47    [20709451]     Ответить | Цитировать Сообщить модератору
 Re: Получить следующее последовательное число, не дающее коллизий  [new]
scoreZ
Guest
Remind, да, это оно, премного благодарствую!
Вот только иногда выдавало значение с коллизией, например (это полный список инсертов, замещающий те, что в примере):

insert into @T2 values ('200008');
insert into @Z values (8);
--результат 7

insert into @T1 values ('100005');
insert into @T2 values ('200003');
insert into @T2 values ('200004');
insert into @T2 values ('200006');
insert into @Z values (2);
--результат 6

Разобрался в логике - походу, проблема решается так:
select isnull(min(rn), (select max(Y) from cte)[b]+1[/b]) from rn where rn <> Y

Ещё раз спасибо за помощь!
8 авг 17, 21:01    [20709471]     Ответить | Цитировать Сообщить модератору
 Re: Получить следующее последовательное число, не дающее коллизий  [new]
scoreZ
Guest
О, болдом в коде нельзя выделять, не подумал ))
8 авг 17, 21:02    [20709473]     Ответить | Цитировать Сообщить модератору
Все форумы / Microsoft SQL Server Ответить