SQL选择或插入返回ID

SQL选择或插入返回ID,sql,sql-server,sql-server-2008,Sql,Sql Server,Sql Server 2008,好的,这里有一个快速的SQL问题(使用SQL-server-2008) 我有一个映射表names,包含以下列 IDDisplayName 我想做的是先 从[name]中选择[ID],其中[DisplayName]=“chuck” 但是,如果数据库中不存在名称“chuck”,我想创建它,并返回自动递增的ID 我想知道SQL是否有一些内置的方法可以轻松地实现这一点,或者我是否必须走很长的路 长途跋涉 SELECT COUNT(ID) AS count, ID FROM names WHERE Dis

好的,这里有一个快速的SQL问题(使用SQL-server-2008)

我有一个映射表
names
,包含以下列

ID
DisplayName

我想做的是先
从[name]中选择[ID],其中[DisplayName]=“chuck”

但是,如果数据库中不存在名称“chuck”,我想创建它,并返回自动递增的
ID

我想知道SQL是否有一些内置的方法可以轻松地实现这一点,或者我是否必须走很长的路

长途跋涉

SELECT COUNT(ID) AS count, ID FROM names WHERE DisplayName='chuck'
IF(count > 0)
    SELECT ID as ReturnID;
ELSE
    BEGIN
    INSERT INTO names(DisplayName) values('chuck');
    SELECT scope_identity() as ReturnID;
    END
我没有测试最后一句话,但我认为还有很长的路要走。如果没有内置的方式,如果有人能简单地纠正这句话,我将不胜感激(因为我确信它不是完全正确的)。

我会:

IF (NOT EXISTS(SELECT null from names where DisplayName='Chuck'))
   INSERT INTO Names (DisplayName) Values ('Chuck')

SELECT ID as ReturnID FROM Names where DisplayName='Chuck'

虽然节省不多,但您也应该注意事务:

set XACT_ABORT on
begin tran

declare @ID int

select @ID = ID from names with (holdlock, updlock) WHERE DisplayName='chuck'

if @@rowcount = 0
begin
  INSERT INTO names(DisplayName) values('chuck');
  set @ID = scope_identity();
end

select @ID as ReturnID;

commit tran
注意表提示的用法-holdlockupdlock。它们阻止另一个线程执行完全相同的查询并再次创建行。有关更多信息,请查看隔离、同步、死锁和并发更新

go
create table names
(
    Id int primary key identity(1,1),
    displayname varchar(100),
);

go
create procedure P1
    @displayname varchar(100)
as
    insert into names (displayname)
    select @displayname
    where not exists (
        select * from names, (select @displayname as displayname) as names2
            where names.displayname = names2.displayname);

    -- race condition is possible here,
    -- but in some cases you still may get away with this

    select id from names where displayname = @displayname;

go  
declare @dn varchar(100);

set @dn = 'chuck'; exec P1 @dn; exec P1 @dn; exec P1 @dn;

set @dn = 'buck'; exec P1 @dn; exec P1 @dn;

select * from names;

go
drop table names; drop procedure P1;

输出将
1,1,1,2,2
,表格内容有两行大。

如果只支持200*+,请使用您能提供一个示例吗?我正在努力学习使用sql的更高级的方法。@kelton52:在文章的末尾有一些例子OMG Ponies linked。你需要向下滚动一点。@zespri我看到了这些例子,但没有一个是我想做的。我通读了这些例子,但不理解它们。此外,如果他把他的评论作为一个例子的答案,我可以选择它。@kelton52这是最后一个使用
OUTPUT
的例子,但这在你的例子中不起作用。它仅在存在插入或更新场景时有效。否则,当记录已经存在时,输出将是空的。好吧,运行这个,现在表已经死锁了…有什么想法吗?你也有两次这样的想法,假设不是有意的,sql也不会识别xac_ABORT基本上每次这个查询都会工作,但是对表的其他查询都不会工作。还要记住,此查询将从一个脚本运行,而不是从一个网站或任何东西运行…因此不会同时有多个查询调用..本质上,它只是一个将CSV值插入数据库的perl脚本,这不是最多执行2个查询,最糟糕的是执行1个查询吗?