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

create database testdb;
go
use testdb;
go

create table dbo.testtbl
(
	sn varchar(15), 
	acc varchar(20), 
	data nvarchar(1024)

	constraint pk__testtbl unique clustered(sn)
);
go

-- Процедура должна уведомить клиентский код,
-- существует ли такая запись и если нет
-- то вставить ее
create procedure dbo.add_data
	@sn varchar(15),
	@acc varchar(20),
	@data nvarchar(1024)
as
begin

	begin try
		begin transaction;

		declare
			@existing_acc varchar(20) =
			(
				select 
					acc 
				from
					-- удерживаем Key Range блокировку до конца транзакции
					-- индекс на sn присутствует pk__testtbl
					testtbl with(serializable)
				where 
					sn = @sn
			);

		if (@existing_acc is not null)
		begin
			return iif(@existing_acc = @acc, -1, -2);
		end;

		insert into dbo.testtbl(sn, acc, data)
		values(@sn, @acc, @data);

		commit transaction;

		return 0;
	end try
	begin catch
		
		if (@@trancount > 0)
			rollback transaction;

		throw;

	end catch
end;
24 апр 15, 11:40    [17558015]     Ответить | Цитировать Сообщить модератору
 Re: Проверить что запись не существует и вставить, иначе уведомить  [new]
Добрый Э - Эх
Guest
Альберт Игнатов,

не совсем понял, что ты хочешь, но возможно - MERGE ?
24 апр 15, 11:46    [17558050]     Ответить | Цитировать Сообщить модератору
 Re: Проверить что запись не существует и вставить, иначе уведомить  [new]
Glory
Member

Откуда:
Сообщений: 104760
Альберт Игнатов
		declare
			@existing_acc varchar(20) =
			(
				select 
					acc 
				from
					-- удерживаем Key Range блокировку до конца транзакции
					-- индекс на sn присутствует pk__testtbl
					testtbl with(serializable)
				where 
					sn = @sn
			);

		if (@existing_acc is not null)
		begin
			return iif(@existing_acc = @acc, -1, -2);
		end;

Вы эти проверяете существование чего ? sn или acc ? Или их пары ?
24 апр 15, 11:52    [17558097]     Ответить | Цитировать Сообщить модератору
 Re: Проверить что запись не существует и вставить, иначе уведомить  [new]
Альберт Игнатов
Guest
Glory
Альберт Игнатов
		declare
			@existing_acc varchar(20) =
			(
				select 
					acc 
				from
					-- удерживаем Key Range блокировку до конца транзакции
					-- индекс на sn присутствует pk__testtbl
					testtbl with(serializable)
				where 
					sn = @sn
			);

		if (@existing_acc is not null)
		begin
			return iif(@existing_acc = @acc, -1, -2);
		end;

Вы эти проверяете существование чего ? sn или acc ? Или их пары ?


Проверяю только наличие sn. А далее просто уточнение для кода выше к текущему @acc принадлежит или к другому. Но важен факт - в таблице вообще есть sn или нет. Если есть то сказать об этом. Если нет - вставить без constraint violation (uk__pk) при возможном конкурентой вставке.

---

Добрый Э - Эх

это его тогда в serializable обернуть, с учетом сказанного выше?
24 апр 15, 11:58    [17558126]     Ответить | Цитировать Сообщить модератору
 Re: Проверить что запись не существует и вставить, иначе уведомить  [new]
Glory
Member

Откуда:
Сообщений: 104760
Альберт Игнатов
Проверяю только наличие sn. А далее просто уточнение для кода выше к текущему @acc принадлежит или к другому. Но важен факт - в таблице вообще есть sn или нет. Если есть то сказать об этом. Если нет - вставить без constraint violation (uk__pk) при возможном конкурентой вставке.

Зачем тогда эти пляски с присвоением acc в переменную и дополнительным ее сравнением ?
Сразу нельзя сделать что ли insert ... select where not exists() с таким же удержанием блокировки ?
24 апр 15, 12:01    [17558142]     Ответить | Цитировать Сообщить модератору
 Re: Проверить что запись не существует и вставить, иначе уведомить  [new]
Альберт Игнатов
Guest
Только там в коде вместо

					testtbl with(serializable)
надо

					testtbl with(serializable, updlock)


иначе deadlock
24 апр 15, 12:01    [17558146]     Ответить | Цитировать Сообщить модератору
 Re: Проверить что запись не существует и вставить, иначе уведомить  [new]
Альберт Игнатов
Guest
Glory
Альберт Игнатов
Проверяю только наличие sn. А далее просто уточнение для кода выше к текущему @acc принадлежит или к другому. Но важен факт - в таблице вообще есть sn или нет. Если есть то сказать об этом. Если нет - вставить без constraint violation (uk__pk) при возможном конкурентой вставке.

Зачем тогда эти пляски с присвоением acc в переменную и дополнительным ее сравнением ?
Сразу нельзя сделать что ли insert ... select where not exists() с таким же удержанием блокировки ?


а мне надо коду выше пояснить что существует (и кому принадлежит @acc... текущему или другому...). чтобы он мог выдать юзерю сообщение побробное.
24 апр 15, 12:03    [17558163]     Ответить | Цитировать Сообщить модератору
 Re: Проверить что запись не существует и вставить, иначе уведомить  [new]
Glory
Member

Откуда:
Сообщений: 104760
Альберт Игнатов
а мне надо коду выше пояснить что существует (и кому принадлежит @acc... текущему или другому...). чтобы он мог выдать юзерю сообщение побробное.

Что ? Вы только что уверяли, что проверять нужно только sn
Какому "другому" может принадлежать @acc, если вы ищите только по одному @sn ?
24 апр 15, 12:07    [17558195]     Ответить | Цитировать Сообщить модератору
 Re: Проверить что запись не существует и вставить, иначе уведомить  [new]
Альберт Игнатов
Guest
Glory
Альберт Игнатов
а мне надо коду выше пояснить что существует (и кому принадлежит @acc... текущему или другому...). чтобы он мог выдать юзерю сообщение побробное.

Что ? Вы только что уверяли, что проверять нужно только sn
Какому "другому" может принадлежать @acc, если вы ищите только по одному @sn ?


все верно. sn - глобален по бизнес логике. проверяем только ЕГО наличие. коду выше важен факт - не существует/существует такой sn в таблице и ПОЯСНЕНИЕ если существует то принадлежит этому же acc или другому (просто чтобы чуть чуть подробее).
24 апр 15, 12:13    [17558248]     Ответить | Цитировать Сообщить модератору
 Re: Проверить что запись не существует и вставить, иначе уведомить  [new]
Владислав Колосов
Member

Откуда:
Сообщений: 7868
Зачем столько кода и вычислений для простейшей операции? Если для определении "схожести " используется ключ, выбрасывайте исключение с заданным номером ошибки.
24 апр 15, 12:22    [17558311]     Ответить | Цитировать Сообщить модератору
 Re: Проверить что запись не существует и вставить, иначе уведомить  [new]
Альберт Игнатов
Guest
Владислав Колосов
Зачем столько кода и вычислений для простейшей операции? Если для определении "схожести " используется ключ, выбрасывайте исключение с заданным номером ошибки.


А как нормально обрабатывать в catch ошибку нарушения уникальности вот именно вот этого индекса? like по message чтоли? чтобы вот эту вот ошибку уникальности конвертнуть в код ошибки приложения? Да еще и узнать текущему @acc принадлиежит существующая запись или всеже другому?

можно пример?
24 апр 15, 12:29    [17558359]     Ответить | Цитировать Сообщить модератору
 Re: Проверить что запись не существует и вставить, иначе уведомить  [new]
invm
Member

Откуда: Москва
Сообщений: 9397
Альберт Игнатов,

Ваш код потенциально дедлочный. Либо перепишите через merge с serializable, либо к serializable добавьте, как минимум, updlock.
24 апр 15, 13:46    [17558922]     Ответить | Цитировать Сообщить модератору
 Re: Проверить что запись не существует и вставить, иначе уведомить  [new]
Владислав Колосов
Member

Откуда:
Сообщений: 7868
Номер сообщения нарушения ограничения ключи фиксирован. А Вы одним запросом разве вставляете запись в несколько таблиц?
24 апр 15, 14:08    [17559072]     Ответить | Цитировать Сообщить модератору
 Re: Проверить что запись не существует и вставить, иначе уведомить  [new]
Альберт Игнатов
Guest
invm
Альберт Игнатов,

Ваш код потенциально дедлочный. Либо перепишите через merge с serializable, либо к serializable добавьте, как минимум, updlock.


17558146
24 апр 15, 14:13    [17559112]     Ответить | Цитировать Сообщить модератору
 Re: Проверить что запись не существует и вставить, иначе уведомить  [new]
Альберт Игнатов
Guest
Владислав Колосов
Номер сообщения нарушения ограничения ключи фиксирован.


Кэп, как мне это поможет. Смотри пример внимательнее. Пусть на таблице есть несколько unique constraints. Какой из них нарушен, как определить по этому самому фикс. коду? Кроме как лайкой по message exception'a вроде никак. А как узнать доп инфу см. пример выше?


Владислав Колосов
А Вы одним запросом разве вставляете запись в несколько таблиц?


а это к чему вопрос? lol
24 апр 15, 14:16    [17559136]     Ответить | Цитировать Сообщить модератору
 Re: Проверить что запись не существует и вставить, иначе уведомить  [new]
Владислав Колосов
Member

Откуда:
Сообщений: 7868
Unique множественные ограничения здесь причем? Вы проверяете дубли по первичному ключу.
Если Вы не выполняете вставку в несколько таблиц, то ошибка нарушения ключа будет единственная и в известной части кода.
24 апр 15, 14:29    [17559237]     Ответить | Цитировать Сообщить модератору
 Re: Проверить что запись не существует и вставить, иначе уведомить  [new]
Альберт Игнатов
Guest
Владислав Колосов
Unique множественные ограничения здесь причем? Вы проверяете дубли по первичному ключу.
Если Вы не выполняете вставку в несколько таблиц, то ошибка нарушения ключа будет единственная и в известной части кода.


use db1;
go

create table t1
(
	a1 int, a2 int, a3 int, a4 int

	constraint uk__t1__a1 unique(a1),
	constraint uk__t1__a2 unique(a2),
	constraint uk__t1__a3 unique(a3),
	constraint uk__t1__a4 unique(a4),
);
go

insert into t1(a1, a2, a3, a4) values(1, 2, 3, 4);
go
insert into t1(a1, a2, a3, a4) values(10, 2, 30, 40);
go
insert into t1(a1, a2, a3, a4) values(10, 20, 30, 4);
go



(1 row(s) affected)
Msg 2627, Level 14, State 1, Line 17
Violation of UNIQUE KEY constraint 'uk__t1__a2'. Cannot insert duplicate key in object 'dbo.t1'. The duplicate key value is (2).
The statement has been terminated.
Msg 2627, Level 14, State 1, Line 19
Violation of UNIQUE KEY constraint 'uk__t1__a4'. Cannot insert duplicate key in object 'dbo.t1'. The duplicate key value is (4).
The statement has been terminated.

24 апр 15, 14:52    [17559449]     Ответить | Цитировать Сообщить модератору
Все форумы / Microsoft SQL Server Ответить