Проверить, существует ли строка, в противном случае вставить

Мне нужно написать Т-SQL хранимой процедуры, которая обновляет строку в таблице. Если строки Не'т существуют, вставьте его. Все это шаги обернутый сделки.

Это системы бронирования, поэтому оно должно быть атомная и надежный. Она должна возвращать true, если транзакция была совершена и забронированный рейс.

Я'м новый в T-SQL В, и не знаете, как использовать функции@@rowcount`. Это то, что я'вэ написано до сих пор. Я на правильном пути? Я'м уверена, что это легкая задача для вас.

-- BEGIN TRANSACTION (HOW TO DO?)

UPDATE Bookings
 SET TicketsBooked = TicketsBooked + @TicketsToBook
 WHERE FlightId = @Id AND TicketsMax < (TicketsBooked + @TicketsToBook)

-- Here I need to insert only if the row doesn't exists.
-- If the row exists but the condition TicketsMax is violated, I must not insert 
-- the row and return FALSE

IF @@ROWCOUNT = 0 
BEGIN

 INSERT INTO Bookings ... (omitted)

END

-- END TRANSACTION (HOW TO DO?)

-- Return TRUE (How to do?)
Комментарии к вопросу (2)

Взгляните на слияние команда. Вы можете сделать обновление, вставить & удалить в одном заявлении.

Вот рабочая реализация на использовании "объединить"

  • Он проверяет, является ли путь, прежде чем делать обновление, иначе не вставить.

если существует(выберите 1 из базы данных information_schema.ТАБЛИЦЫ Т где Т. ИМЯ_ТАБЛИЦЫ = 'заказы') начать падение заказов стол конец Перейти

создайте заказа столиков( FlightID инт идентичности(1, 1) первичного ключа, TicketsMax инт не null, TicketsBooked инт не null ) Перейти

вставка заказы(TicketsMax, TicketsBooked) выберите 1, 0 вставка заказы(TicketsMax, TicketsBooked) выберите 2, 2 вставка заказы(TicketsMax, TicketsBooked) выберите 3, 1 Перейти

выбрать * из заказа

И потом ...

declare @FlightID int = 1
declare @TicketsToBook int = 2

--; This should add a new record
merge Bookings as T
using (select @FlightID as FlightID, @TicketsToBook as TicketsToBook) as S
    on  T.FlightID = S.FlightID
      and T.TicketsMax > (T.TicketsBooked + S.TicketsToBook)
  when matched then
    update set T.TicketsBooked = T.TicketsBooked + S.TicketsToBook
  when not matched then
    insert (TicketsMax, TicketsBooked) 
    values(S.TicketsToBook, S.TicketsToBook);

select * from Bookings
Комментарии (3)

Я предполагаю одну строку для каждого рейса? Если так:

IF EXISTS (SELECT * FROM Bookings WHERE FLightID = @Id)
BEGIN
    --UPDATE HERE
END
ELSE
BEGIN
   -- INSERT HERE
END

Я предполагаю, что я сказал, А ваш способ делать вещи могут перебронировали на рейс, так как он будет вставлять новую строку, когда есть 10 билетов максимум и вы бронируете 20.

Комментарии (7)

Пройти updlock, уключины, аргумент holdlock подсказки при проверке на наличие строки.

в <предварительно><код>начать Тран / по умолчанию уровень изоляции чтения зафиксированных в порядке /

если не существует (выберите от стола с (updlock, уключины, аргумент holdlock), где ...) / вставить / еще / обновление */

фиксации / замки выпускаются здесь / </код></пре>

Подсказку updlock сил запрос взять блокировку обновления на строку, если она уже существует, не давая другим транзакциям изменять его до фиксации или отката.

Этот аргумент holdlock намек заставляет запроса блокировки диапазона, предотвращая другие операции добавления строки, соответствующей вашим критериям фильтра до фиксации или отката.

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

См http://msdn.microsoft.com/en-us/library/ms187373.aspx для получения дополнительной информации.

Обратите внимание, что замки берутся в качестве заявления, что принимать их будут казнить вызывая начать Тран не'т дать вам иммунитет против другой транзакцией щипать замки на что-то, прежде чем добраться до него. Вы должны попробовать и фактор своего SQL, чтобы держать замки в кратчайшие сроки путем совершения сделки как можно скорее (приобретать начале конце, релизе).

Обратите внимание, что блокировки на уровне строк может быть менее эффективным, если ваш ПК имеет тип bigint, как внутреннего хеширования на SQL Server-это дегенеративное для 64-разрядных значений (различных основных значения хэш один и тот же идентификатор блокировки).

Комментарии (4)

я'м пишу мое решение. мой метод не'т стоять 'если бы' или 'слияние'. мой метод прост.

INSERT INTO TableName (col1,col2)
SELECT @par1, @par2
   WHERE NOT EXISTS (SELECT col1,col2 FROM TableName
                     WHERE col1=@par1 AND col2=@par2)

Например:

INSERT INTO Members (username)
SELECT 'Cem'
   WHERE NOT EXISTS (SELECT username FROM Members
                     WHERE username='Cem')

Объяснение:

(1) Выберите столбец col1,столбец col2 from Имя_таблицы где col1=@парам1 и col2=@парам2 Он выбирает из таблицы искали ценности

(2) Выберите @парам1, @парам2, где не существует Это нужно, если не существует из (1) подзапрос

(3) вставки в tableName (2) шаг значений

Комментарии (2)

Я, наконец, смог вставить строку, при условии, что это не'т уже существуют, используя следующую модель:

INSERT INTO table ( column1, column2, column3 )
(
    SELECT $column1, $column2, $column3
      WHERE NOT EXISTS (
        SELECT 1
          FROM table 
          WHERE column1 = $column1
          AND column2 = $column2
          AND column3 = $column3 
    )
)

который я нашел по адресу:

http://www.postgresql.org/message-id/87hdow4ld1.fsf@stark.xeocode.com

Комментарии (1)

Это я просто недавно пришлось делать:

set ANSI_NULLS ON
set QUOTED_IDENTIFIER ON
GO
ALTER PROCEDURE [dbo].[cjso_UpdateCustomerLogin]
    (
      @CustomerID AS INT,
      @UserName AS VARCHAR(25),
      @Password AS BINARY(16)
    )
AS 
    BEGIN
        IF ISNULL((SELECT CustomerID FROM tblOnline_CustomerAccount WHERE CustomerID = @CustomerID), 0) = 0
        BEGIN
            INSERT INTO [tblOnline_CustomerAccount] (
                [CustomerID],
                [UserName],
                [Password],
                [LastLogin]
            ) VALUES ( 
                /* CustomerID - int */ @CustomerID,
                /* UserName - varchar(25) */ @UserName,
                /* Password - binary(16) */ @Password,
                /* LastLogin - datetime */ NULL ) 
        END
        ELSE
        BEGIN
            UPDATE  [tblOnline_CustomerAccount]
            SET     UserName = @UserName,
                    Password = @Password
            WHERE   CustomerID = @CustomerID    
        END

    END
Комментарии (1)

Вы можете использовать слияние функциональные возможности для достижения. В противном случае вы можете сделать:

declare @rowCount int

select @rowCount=@@RowCount

if @rowCount=0
begin
--insert....
Комментарии (2)

Полное решение ниже (включая структуру курсора). Большое спасибо Поркус Кассия для начала транс ... обязательства` код из постинга выше.

declare @mystat6 bigint
declare @mystat6p varchar(50)
declare @mystat6b bigint

DECLARE mycur1 CURSOR for

 select result1,picture,bittot from  all_Tempnogos2results11

 OPEN mycur1

 FETCH NEXT FROM mycur1 INTO @mystat6, @mystat6p , @mystat6b

 WHILE @@Fetch_Status = 0
 BEGIN

 begin tran /* default read committed isolation level is fine */

 if not exists (select * from all_Tempnogos2results11_uniq with (updlock, rowlock, holdlock)
                     where all_Tempnogos2results11_uniq.result1 = @mystat6 
                        and all_Tempnogos2results11_uniq.bittot = @mystat6b )
     insert all_Tempnogos2results11_uniq values (@mystat6 , @mystat6p , @mystat6b)

 --else
 --  /* update */

 commit /* locks are released here */

 FETCH NEXT FROM mycur1 INTO @mystat6 , @mystat6p , @mystat6b

 END

 CLOSE mycur1

 DEALLOCATE mycur1
 go
Комментарии (0)
INSERT INTO [DatabaseName1].dbo.[TableName1] SELECT * FROM [DatabaseName2].dbo.[TableName2]
 WHERE [YourPK] not in (select [YourPK] from [DatabaseName1].dbo.[TableName1])
Комментарии (0)

Лучший подход к этой проблеме является первым создание уникального столбца базы данных

Инструкции ALTER TABLE имя_таблицы добавить уникальный ключ

Затем вставить игнорировать в имя_таблицы` ,значение выиграл'т быть вставлен, если он приводит к дублировать ключ уже существует в таблице.

Комментарии (1)
INSERT INTO table ( column1, column2, column3 )
SELECT $column1, $column2, $column3
EXCEPT SELECT column1, column2, column3
FROM table
Комментарии (2)