![]() |
| ||
|
|
Новости |
Поиск |
FAQ |
Статьи |
Книги |
Новости VCL
| | Форумы ЧАТ |
Орешник |
|
| |||
| |||
« предыдущая ветвь | форум | следующая ветвь »
запрос sql: если есть изменить запись если нет то добавить запись [D7, MSSQL]
redlord © (2005-07-17 21:26:00)всем привет
народ помогите составить запрос sql к базе mssql
имеется таблица с тремя полями f1 f2 f3 записи в f1 уникальны
мне нужно добавлять строку тока в том случае если значение из добавляемой строки в поле f1 не совпадает ни с одним значение поля F1 уже имеющихся в таблице.а если совпадают то поменять у уже имеюжейся записи значение поля f2
redlord (2005-07-18 23:51:00) [1]очен жалко что позно зашол на ветку да и сечас уже поздно а завтра обязательно изучу все посты
спасибо всем откликнувшимся
Fay (2005-07-18 11:46:00) [2]Сам проверил - всё ОК.
Остаётся только тщательней следить за захватом ресурсов воизбежание deadlock-ов.
MOA (2005-07-18 11:45:00) [3]>evvcom © (18.07.05 11:38) [29]
>> WAITFOR DELAY '00:00:05'
>А это зачем?
А это чтобы наглядно проверить (чтобы кнопулю успеть нажать во втором сеансе), что транзакции отрабатывают как надо - моделируем так сказать, ситуацию, когда два процесса проверили - и оба получили, что записи нет - оба пытаются вставить, что нехорошо :).
MOA (2005-07-18 11:43:00) [4]>Fay © (18.07.05 11:34) [28]
>INSERT-ом проверял?
Угу. Во втором сеансе запускалось почти то же:
SET TRANSACTION ISOLATION LEVEL SERIALIZABLE
GO
BEGIN TRANSACTION
IF EXISTS(SELECT * FROM t4 WITH (UPDLOCK) WHERE f1=3)
BEGIN
WAITFOR DELAY '00:00:05'
UPDATE t4 SET f2=2223 WHERE f1=3
END
ELSE
BEGIN
WAITFOR DELAY '00:00:05'
INSERT INTO t4 (f1, f2, f3) VALUES (3, 2003, 3003)
END
COMMIT TRANSACTION
Результат - всё как надо, ждёт инсерта с первого сеанса, потом апдейтит (записи с f1=3 в таблице первоначально нет).
evvcom (2005-07-18 11:38:00) [5]
> WAITFOR DELAY '00:00:05'
А это зачем? Искусственные тормоза? Делай [2] и хватит ерундой заниматься с кучей лишних запросов, да еще искусственных задержек.
Fay (2005-07-18 11:34:00) [6]2 MOA © (18.07.05 11:02) [22]
INSERT-ом проверял?
evvcom (2005-07-18 11:19:00) [7]А [6], кстати, может быть чревато последствиями. Нехорошими
еще с большей вероятностью. Имхо.
evvcom (2005-07-18 11:15:00) [8]
> что может быть чревато последствиями. Нехорошими
Сейчас в хелпе этого не увидел, но раньше читал, что если читать из @@ROWCOUNT сразу же за селектом, апдейтом и т.п., то это гарантирует, что она покажет именно нужное значение. А иначе зачем было мелкомягким вводить такую переменную, если ей нельзя доверять на 100%?
ЮЮ (2005-07-18 11:15:00) [9]Честно говоря, хотелось бы автора услушать, откуда такое желание возникло, точнее откуда это f1 взялось.
Если из этой же базы, то к чему такие извращения. Ведь если f1 определен, то запись есть и её надо редактировать. Даже если её уже не стало, то зачем вставлять, если её только что кто-то удалил? А если запись новая, то откуда f1 на клиенте? Его должен тогда сервер определить, ибо два клиента по одному и тому же алгоритму получат одно и тоже значение для новой записи, а это не лучше, чем в случае Fay © (18.07.05 10:17) [19]
Если же это внешние данные, то ситуация описанная в [19]
тоже притянута за уши, т.к. если из двух разных пакетов путаются вставить разные записи (разные f2 или f3 для одинакового f1), то это уже ошибка, независимо от поведения сервера, а если одинаковые, то не важно из какого пакета она добавится. А добавление 2х записей невозможно ввиду " f1 уникальны"
ЮЮ (2005-07-18 11:14:00) [10]>В [2] ты привязываешься к глобальной переменной @@ROWCOUNT
Может тогда и @@ERROR небезопасно смотреть, ведь там может оказаться чужая ошибка :)
if @@ROWCOUNT = 0 - впримере из BOL стоит
Ega23 (2005-07-18 11:03:00) [11]2 evvcom © (18.07.05 10:29) [21]
А [2] что такое?
В [2] ты привязываешься к глобальной переменной @@ROWCOUNT, что может быть чревато последствиями. Нехорошими.
MOA (2005-07-18 11:02:00) [12]Прошло вот так:
CREATE TABLE [t4] (
[f1] [int] NOT NULL ,
[f2] [int] NULL ,
[f3] [int] NULL ,
CONSTRAINT [PK_t4] PRIMARY KEY CLUSTERED
(
[f1]
) ON [PRIMARY]
) ON [PRIMARY]
GO
SET TRANSACTION ISOLATION LEVEL SERIALIZABLE
GO
BEGIN TRANSACTION
IF EXISTS(SELECT * FROM t4 WITH (UPDLOCK) WHERE f1=3)
BEGIN
WAITFOR DELAY '00:00:05'
UPDATE t4 SET f2=223 WHERE f1=3
END
ELSE
BEGIN
WAITFOR DELAY '00:00:05'
INSERT INTO t4 (f1, f2, f3) VALUES (3, 203, 303)
END
COMMIT TRANSACTION
Т.е. с уровнем транзакции SERIALIZABLE и хинтом на экзисте UPDLOCK - всё ждёт как надо кого надо ;).
evvcom (2005-07-18 10:29:00) [13]
> Честно говоря, я ждал Вышего решения задачи, а не проповеди
А [2] что такое?
Ega23 (2005-07-18 10:20:00) [14]2 Fay © (18.07.05 10:17) [19]
Ты меня опередил... :о)
Fay (2005-07-18 10:17:00) [15]2 evvcom © (18.07.05 10:06) [18]
Честно говоря, я ждал Вышего решения задачи, а не проповеди.
2 ЮЮ © (18.07.05 9:58) [14]
Открываем QA. В одном окне пишем
use pubs
go
if object_id('QWE') is not null
drop table QWE
go
create table QWE(
CODE int not null,
NAME varchar(32) collate SQL_Latin1_General_CP1251_CI_AS not null,
constraint PK_QWE primary key nonclustered(CODE),
constraint UNQ_QWE_NAME unique(NAME)
)
go
insert into QWE (CODE, NAME) values (1, '1')
insert into QWE (CODE, NAME) values (2, '2')
insert into QWE (CODE, NAME) values (3, '3')
go
declare
@n int,
@s varchar(32),
@dt datetime
select
@n = 2,
@s = 'Два',
@dt = '00:00:05'
begin tran
if exists(select * from QWE where CODE = @n)
begin
waitfor delay @dt
update QWE set NAME = @s where CODE = @n
end
else
begin
waitfor delay @dt
insert into QWE (CODE, NAME) values (@n, @s)
end
select [row count] = @@rowcount
commit tran
go
drop table QWE
, а в другом
use pubs
delete from QWE where CODE = 2
Запускаем сначала 1-й, и пока он думает, 2-й скрипт.
Внимательно смотрим на [row count]
evvcom (2005-07-18 10:06:00) [16]
> Внимательно жду(ждём) подробностей.
А чего непонятно? В обоих случаях используется сначала select (1-ый скан), потом update (2-ой скан). А индексы тут не при чем, они на количество сканов никак не влияют. На продолжительность (объем перебора и т.п.) да, но на количество...
Anatoly Podgoretsky (2005-07-18 10:01:00) [17]Она естественно никуда не денется, но может оказаться добавленой в промежутке между SELECT и INSERT
Fay (2005-07-18 10:00:00) [18]2 ЮЮ © (18.07.05 9:58) [14]
... или появится
Fay (2005-07-18 10:00:00) [19]2 ЮЮ © (18.07.05 9:58) [14]
Денется, ещё как.
2 Anatoly Podgoretsky © (18.07.05 9:56) [13]
А что Вы имели ввиду, говоря про наличие таких триггеров?
ЮЮ (2005-07-18 09:58:00) [20]>Удача явно потребуется, т.к. между
>IF EXISTS(SELECT * FROM t WHERE f1=..)
>и
>UPDATE ....
>запись может быть удалена/добавлена
Если в рамках одной транзакции, а между ними нет закрытия ожной и старта новой транзакции, то никуда она не денется