ЕСЛИ СУЩЕСТВУЕТ, ТО ВЫБЕРИТЕ, ЕЩЕ ВСТАВЛЯЮТ И ЗАТЕМ ВЫБИРАЮТ

Если бы это - инициализация, это, вероятно, было бы iostream заголовок с (как istream, ios, и т.д.).

49
задан OMG Ponies 28 September 2009 в 06:41
поделиться

6 ответов

You need to do this in transaction to ensure two simultaneous clients won't insert same fieldValue twice:

SET TRANSACTION ISOLATION LEVEL SERIALIZABLE
BEGIN TRANSACTION
    DECLARE @id AS INT
    SELECT @id = tableId FROM table WHERE fieldValue=@newValue
    IF @id IS NULL
    BEGIN
       INSERT INTO table (fieldValue) VALUES (@newValue)
       SELECT @id = SCOPE_IDENTITY()
    END
    SELECT @id
COMMIT TRANSACTION

you can also use Double-checked locking to reduce locking overhead

DECLARE @id AS INT
SELECT @id = tableID FROM table (NOLOCK) WHERE fieldValue=@newValue
IF @id IS NULL
BEGIN
    SET TRANSACTION ISOLATION LEVEL SERIALIZABLE
    BEGIN TRANSACTION
        SELECT @id = tableID FROM table WHERE fieldValue=@newValue
        IF @id IS NULL
        BEGIN
           INSERT INTO table (fieldValue) VALUES (@newValue)
           SELECT @id = SCOPE_IDENTITY()
        END
    COMMIT TRANSACTION
END
SELECT @id

As for why ISOLATION LEVEL SERIALIZABLE is necessary, when you are inside a serializable transaction, the first SELECT that hits the table creates a range lock covering the place where the record should be, so nobody else can insert the same record until this transaction ends.

Without ISOLATION LEVEL SERIALIZABLE, the default isolation level (READ COMMITTED) would not lock the table at read time, so between SELECT and UPDATE, somebody would still be able to insert. Transactions with READ COMMITTED isolation level do not cause SELECT to lock. Transactions with REPEATABLE READS lock the record (if found) but not the gap.

60
ответ дан 7 November 2019 в 11:35
поделиться
IF EXISTS (SELECT 1 FROM Table WHERE FieldValue='') 
BEGIN
   SELECT TableID FROM Table WHERE FieldValue=''
END
ELSE
BEGIN
   INSERT INTO TABLE(FieldValue) VALUES('')
   SELECT SCOPE_IDENTITY() AS TableID
END

See here for more information on IF ELSE

Note: written without a SQL Server install handy to double check this but I think it is correct

Also, I've changed the EXISTS bit to do SELECT 1 rather than SELECT * as you don't care what is returned within an EXISTS, as long as something is Я также изменил бит SCOPE_IDENTITY (), чтобы он возвращал только идентификатор, предполагая, что TableID является столбцом идентификатора

32
ответ дан 7 November 2019 в 11:35
поделиться

You were close:

IF EXISTS (SELECT * FROM Table WHERE FieldValue='')
   SELECT TableID FROM Table WHERE FieldValue=''
ELSE
BEGIN
   INSERT INTO TABLE (FieldValue) VALUES ('')
   SELECT TableID FROM Table WHERE TableID=SCOPE_IDENTITY()
END
7
ответ дан 7 November 2019 в 11:35
поделиться

Вам просто нужно немного изменить структуру if ... else..endif :

if exists(select * from Table where FieldValue='') then begin
  select TableID from Table where FieldValue=''
end else begin
  insert into Table (FieldValue) values ('')
  select TableID from Table where TableID = scope_identity()
end

Вы также можете сделать:

if not exists(select * from Table where FieldValue='') then begin
  insert into Table (FieldValue) values ('')
end
select TableID from Table where FieldValue=''

Или:

if exists(select * from Table where FieldValue='') then begin
  select TableID from Table where FieldValue=''
end else begin
  insert into Table (FieldValue) values ('')
  select scope_identity() as TableID
end
2
ответ дан 7 November 2019 в 11:35
поделиться
DECLARE @t1 TABLE (
    TableID     int         IDENTITY,
    FieldValue  varchar(20)
)

--<< No empty string
IF EXISTS (
    SELECT *
    FROM @t1
    WHERE FieldValue = ''
) BEGIN
    SELECT TableID
    FROM @t1
    WHERE FieldValue=''
END
ELSE BEGIN
    INSERT INTO @t1 (FieldValue) VALUES ('')
    SELECT SCOPE_IDENTITY() AS TableID
END

--<< A record with an empty string already exists
IF EXISTS (
    SELECT *
    FROM @t1
    WHERE FieldValue = ''
) BEGIN
    SELECT TableID
    FROM @t1
    WHERE FieldValue=''
END
ELSE BEGIN
    INSERT INTO @t1 (FieldValue) VALUES ('')
    SELECT SCOPE_IDENTITY() AS TableID
END
1
ответ дан 7 November 2019 в 11:35
поделиться

Похоже, у вашей таблицы нет ключа. У вас должна быть возможность просто попробовать INSERT : если это дубликат, то ограничение ключа сработает, и INSERT завершится ошибкой. Не беспокойтесь: вам просто нужно убедиться, что приложение не видит / не игнорирует ошибку. Когда вы говорите «первичный ключ», вы, вероятно, имеете в виду значение IDENTITY . Это все очень хорошо, но вам также необходимо ключевое ограничение (например, UNIQUE ) для вашего естественного ключа.

Кроме того, мне интересно, не слишком ли много делает ваша процедура. Рассмотрите возможность использования отдельных процедур для действий «создание» и «чтение» соответственно.

2
ответ дан 7 November 2019 в 11:35
поделиться
Другие вопросы по тегам:

Похожие вопросы: