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

问题描述 投票:0回答:12

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

这是一个预订系统,因此它必须是“原子且可靠的”。如果交易已提交且航班已预订,则它必须返回 true。 我确定如何使用

@@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?)

	
sql sql-server sql-server-2008 t-sql
12个回答
203
投票

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

我假设我所说的,因为你的做法可能会超额预订航班,因为当最多 10 张机票而你预订 20 张机票时,它会插入一个新行。


173
投票

MERGE 命令。您可以在一条语句中执行 UPDATE

INSERT
DELETE

这是使用

MERGE

 的工作实现
- 在进行更新之前检查航班是否已满,否则进行插入。

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



74
投票

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 提示强制查询在该行已存在时获取更新锁,以防止其他事务修改它,直到您提交或回滚。

holdlock 提示强制查询采用范围锁,防止其他事务添加与您的过滤条件匹配的行,直到您提交或回滚。

行锁提示强制锁定粒度为行级别而不是默认页面级别,因此您的事务不会阻止尝试更新同一页面中不相关行的其他事务(但要注意减少争用和增加争用之间的权衡)在锁定开销中 - 您应该避免在单个事务中获取大量行级锁)。

请参阅

http://msdn.microsoft.com/en-us/library/ms187373.aspx

了解更多信息。 请注意,锁被视为执行获取它们的语句 - 调用 begin tran 并不能让您免受另一个事务在您到达某事物之前夹住锁的影响。 您应该尝试并考虑您的 SQL,通过尽快提交事务(晚获取,早释放)来尽可能短地持有锁。

请注意,如果您的 PK 是 bigint,行级锁的效果可能会较差,因为 SQL Server 上的内部哈希对于 64 位值来说是退化的(不同的键值可能会哈希到相同的锁 ID)。


50
投票

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,其中 col1=@par1 AND col2=@par2 它从 TableName 搜索值中选择

(2) 在不存在的情况下选择@par1、@par2 如果不存在则需要 (1) 子查询

(3) 插入 TableName (2) 步骤值


9
投票

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/

[电子邮件受保护]


3
投票

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....



1
投票
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



1
投票


0
投票

--Insert a new record INSERT INTO dbo.Table2(NoEtu, FirstName, LastName) SELECT t1.NoEtuDos, t1.FName, t1.LName FROM dbo.Table1 as t1 WHERE NOT EXISTS (SELECT (1) FROM dbo.Table2 AS t2 WHERE t1.FName = t2.FirstName AND t1.LName = t2.LastName AND t1.NoEtuDos = t2.NoEtu)



-2
投票


-2
投票

ALTER TABLE table_name ADD UNIQUE KEY


THEN INSERT IGNORE INTO table_name

,如果导致重复键/表中已存在该值,则不会插入该值。

    

© www.soinside.com 2019 - 2024. All rights reserved.