如果EXISTS,那么选择ELSE INSERT然后选择

时间:2009-09-28 17:38:05

标签: sql sql-server sql-server-2005 tsql

如何在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并返回相应的主键。

7 个答案:

答案 0 :(得分:60)

您需要在事务中执行此操作以确保两个并发客户端不会两次插入相同的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

您还可以使用Double-checked locking来降低锁定开销

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会创建一个范围锁,覆盖记录所在的位置,所以没有其他人可以插入相同的记录,直到这个交易结束。

如果没有ISOLATION LEVEL SERIALIZABLE,默认隔离级别(READ COMMITTED)将不会在读取时锁定表,因此在SELECT和UPDATE之间,某人仍然可以插入。具有READ COMMITTED隔离级别的事务不会导致SELECT锁定。使用REPEATABLE READS的事务会锁定记录(如果找到)而不是间隙。

答案 1 :(得分:31)

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

的更多信息,请参阅here

注意:在没有SQL Server安装的情况下编写,以便仔细检查这一点,但我认为这是正确的

另外,我已经将EXISTS位更改为SELECT 1而不是SELECT *,因为你不关心在EXISTS中返回什么,只要有什么东西是 我还改变了SCOPE_IDENTITY()位,只返回标识,假设TableID是标识列

答案 2 :(得分:7)

你很亲密:

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

答案 3 :(得分:2)

您只需稍微改变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

答案 4 :(得分:2)

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

另外,我想知道你的程序是否做得太多了。考虑分别为“创建”和“读取”操作设置单独的过程。

答案 5 :(得分:1)

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

答案 6 :(得分:1)

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('')