如果存在,则select其他插入,然后select

你如何在Microsoft SQL Server 2005中说下面的内容:

IF EXISTS (SELECT * FROM Table WHERE FieldValue='') THEN SELECT TableID FROM Table WHERE FieldValue='' ELSE INSERT INTO TABLE(FieldValue) VALUES('') SELECT TableID FROM Table WHERE TableID=SCOPE_IDENTITY() END IF 

我想要做的是看看是否有一个空白fieldvalue,如果有,然后返回该TableID,否则插入一个空白的fieldvalue并返回相应的主键。

您需要在事务中执行此操作,以确保两个并发客户端不会两次插入相同的fieldValue:

 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 

您也可以使用双重检查locking来减lesslocking开销

 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 

至于为什么ISOLATION LEVEL SERIALIZABLE是必要的,当你在一个可序列化的事务中时,第一个到达该表的SELECT将创build一个覆盖logging应该位置的范围锁,所以在这个事务结束之前,没有其他人可以插入相同的logging。

没有ISOLATION LEVEL SERIALIZABLE,默认隔离级别(READ COMMITTED)不会在读取时locking表,所以在SELECT和UPDATE之间,有人仍然可以插入。 具有READ COMMITTED隔离级别的事务不会导致SELECTlocking。 使用REPEATABLE READS的事务会lockinglogging(如果find),但不locking间隔。

 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 

有关IF ELSE的更多信息,请参阅此处

注意:在没有安装SQL Server的情况下安装方便地仔细检查,但我认为是正确的

此外,我已经改变了EXISTS位来做SELECT 1而不是SELECT *,因为你不关心在EXISTS中返回什么,只要有一点是我也改变了SCOPE_IDENTITY()位来返回标识符假设TableID是标识列

你近了:

 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 

你只需要改变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 

听起来你的桌子没有钥匙。 你应该能够简单地尝试INSERT :如果它是重复的,那么关键约束将会咬, INSERT将失败。 不用担心:您只需确保应用程序不会看到/忽略错误。 当你说'主键'你可能意味着IDENTITY值。 这一切都很好,但你也需要一个关键约束(例如UNIQUE )在你的自然键上。

另外,我想知道你的程序是否做得太多了。 考虑分别为“创build”和“读取”操作分别制定程序。

 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 
 create schema tableName authorization dbo go IF OBJECT_ID ('tableName.put_fieldValue', 'P' ) IS NOT NULL drop proc tableName.put_fieldValue go create proc tableName.put_fieldValue(@fieldValue int) as declare @tableid int = 0 select @tableid = tableid from table where fieldValue='' if @tableid = 0 begin insert into table(fieldValue) values('') select @tableid = scope_identity() end return @tableid go declare @tablid int = 0 exec @tableid = tableName.put_fieldValue('')