检查是否存在行,否则插入

我需要编写一个T-SQL存储过程来更新表中的一行。 如果该行不存在,则插入该行。 所有这些步骤都包含在一个事务中。

这是一个预订系统,所以它必须是primefaces和可靠的 。 如果交易已经完成并且预订了航class,它必须返回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?) 

看看MERGE命令。 您可以在一个语句中执行UPDATEINSERTDELETE

这是使用MERGE一个工作实现
– 在更新之前检查航class是否已满,否则请插入。

 if exists(select 1 from INFORMATION_SCHEMA.TABLES T where T.TABLE_NAME = 'Bookings') begin drop table Bookings end GO create table Bookings( FlightID int identity(1, 1) primary key, TicketsMax int not null, TicketsBooked int not null ) GO insert Bookings(TicketsMax, TicketsBooked) select 1, 0 insert Bookings(TicketsMax, TicketsBooked) select 2, 2 insert Bookings(TicketsMax, TicketsBooked) select 3, 1 GO select * from Bookings 

接着 …

 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 

我假设每个航class单行? 如果是这样:

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

我假设我所说的,因为你的做事方式可能会超额预订航class,因为当有最多10张票,而你预订的时候,它会插入一个新的行。

在testing行的存在时传递updlock,rowlock,holdlock提示。

 begin tran /* default read committed isolation level is fine */ if not exists (select * from Table with (updlock, rowlock, holdlock) where ...) /* insert */ else /* update */ commit /* locks are released here */ 

如果已经存在,则updlock提示会强制查询对行进行更新locking,以防止其他事务在您提交或回滚之前对其进行修改。

挂起提示强制查询进行范围locking,防止其他事务添加符合过滤条件的行,直到您提交或回滚。

行锁提示强制将粒度locking到行级别而不是默认页级别,因此您的事务不会阻止其他事务尝试更新同一页面中不相关的行(但请注意减less的争用和增加locking开销 – 您应该避免在单个事务中使用大量的行级锁)。

有关更多信息,请参阅http://msdn.microsoft.com/en-us/library/ms187373.aspx

请注意,锁被视为执行它们的语句 – 调用开始tran不会让您免于另一个事务在您到达之前捏住某个事物的锁。 你应该尝试尽可能快地提交交易(迟到,早发行),尽可能地缩短SQL的locking时间。

请注意,如果您的PK是bigint,则行级别的locking可能效率会降低,因为SQL Server上的内部散列对于64位值(对于相同的lockingID,可能散列不同的键值)会退化。

我正在写我的解决scheme。 我的方法不支持“如果”或“合并”。 我的方法很简单。

 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)SELECT col1,col2 FROM TableName WHERE col1 = @ par1 AND col2 = @ par2它从TableName中selectsearch值

(2)SELECT @ par1,@ par2 WHERE NOT EXISTS如果不存在(1)子查询,

(3)插入到TableName(2)中的步骤值

这是我最近不得不做的事情:

 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 

您可以使用合并function来实现。 否则,你可以这样做:

 declare @rowCount int select @rowCount=@@RowCount if @rowCount=0 begin --insert.... 

下面是完整的解决scheme(包括游标结构)。 非常感谢Cassius Porcus从上面发布的begin trans ... commit代码。

 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 

我终于能够插入一个行,在不存在的情况下,使用下面的模型:

 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

 INSERT INTO Database.dbo.Table SELECT * FROM Database.dbo.Table WHERE ID not in (select ID from Database.dbo.Table) 
 INSERT INTO table ( column1, column2, column3 ) SELECT $column1, $column2, $column3 EXCEPT SELECT column1, column2, column3 FROM table