INSERT IF NOT NOT EXISTS但以任何方式返回身份

时间:2011-11-06 21:01:49

标签: sql sql-server sql-server-2008-r2

我有3个表:audioFormats,videoFormats和fileInfo。 我有一个事务,当我插入fileInfo表时,该插入包括来自audioFormats和videoFormats的FK。如果音频格式或视频格式不在这些表中,则会插入后面的表格,然后将生成的(或现有的)ID值插入到fileInfo中。

如果该值不存在,我如何有效地插入值,但是获取值的ID,无论它是否已经存在,或者仅使用SQL(可能是事务)重新插入。

我可以插入一个值,如果它尚不存在:

INSERT INTO audioformats (audioformat)
VALUES(@format)
WHERE NOT EXISTS (SELECT 1 FROM audioformats WHERE audioformat = @format)

我可以从插入中获取插入的ID:

INSERT INTO audioFormats (audioFormat)
VALUES ('Test')
SET @audioFormatId = SCOPE_IDENTITY()

如果没有插入,SCOPE_IDENTITY将不会给我ID值。 我可以执行标量查询以在可能的插入后获取标识,但似乎我应该能够使用最多一个SELECT和INSERT完成所有这些。

5 个答案:

答案 0 :(得分:13)

您可以使用IF语句执行此操作

IF NOT EXISTS(SELECT TOP 1 1 FROM audioformats WHERE audioformat = @format)
BEGIN
  INSERT INTO audioFormats (audioFormat)
  VALUES ('Test')
  SET @audioFormatId = SCOPE_IDENTITY()
END
ELSE
BEGIN
  SELECT @audioFormatID = ID FROM audioformats WHERE audioformat = @format
END

或者你可以这样做:

INSERT INTO audioformats (audioformat)
  SELECT @format
  FROM audioFormats
  WHERE NOT EXISTS (SELECT TOP 1 1 FROM audioformats WHERE audioformat = @format)

SELECT @audioFormatID = ID FROM audioformats WHERE audioformat = @format

答案 1 :(得分:4)

我将答案标记为正确,因为它与我的最终SQL最相似,但它并没有真正满足最多使用一个查询和一个插入的原始要求。以下是,我最终使用的是:

-- One select
SELECT @audioFormatId = id
FROM audioformats
WHERE audioformat = @audioFormat;

-- Optionally one insert
IF @audioFormatId IS NULL AND @audioFormat IS NOT NULL
BEGIN
    INSERT INTO audioFormats (audioFormat)
    VALUES (@audioFormat)
    SET @audioFormatId = SCOPE_IDENTITY()
END
当大多数对查询的调用确实执行插入时,Hogan的答案可能会更快,因为IF NOT EXISTS查询比实际返回行的查询要快。

在大多数情况下值已经存在的情况下,我的可能会更快,因为那时只会产生一个查询(并且没有IF NOT EXISTS查询)。我怀疑无效检查是微不足道的。

答案 2 :(得分:3)

我认为您可以使用MERGE

这为您提供了无交易的解决方案。一些明亮的火花可能能够使用output子句来改善这一点,以获得目标ID,但下面的工作正常。

我在下面添加了一个指向StackOverflow查询测试器的链接。

-- Merge example
-- Get ID of existing row or insert new row

-- Initialise unit test data
declare @AudioFormatId int;
declare @AudioFormat nvarchar(50)
declare @tblAudioFormats TABLE (AudioFormatId int identity, AudioFormat nvarchar(50)   );
insert into @tblAudioFormats(AudioFormat) values ('MP3'), ('WAV');

-- set query criteria
set @AudioFormat = 'MP3' -- query below returns 1 - updating MP3
--set @AudioFormat = 'WAV' -- query below returns 2 - updating WAV
--set @AudioFormat = 'MIDI' -- query below returns 3 - inserting MIDI

-- Insert or update AudioFormat and return id of target audio format.
merge
  @tblAudioFormats as Target
using
  (select @AudioFormat as AudioFormat) as source(AudioFormat)
on 
  (source.AudioFormat = target.AudioFormat)
when matched then
  update set @AudioFormatID = target.AudioFormatId
when not matched then
  insert(AudioFormat) values (source.AudioFormat);

if @AudioFormatId is null set @AudioFormatId = scope_identity()

-- return ID of target audio format
select @AudioFormatId as TargetAudioFormatId

在此处运行此查询:Query StackOverflow link for sample

答案 3 :(得分:2)

如果audioFormats表具有自动增量IDENTITY(1,1) PK,您可以通过简单的选择获得刚插入的ID:

SELECT MAX(ID) FROM audioFormats 

修改

正如评论中所提到的,只有一个查询插入表中时,此方法才适用。

否则,您可以查看IDENT_CURRENT('table_name')函数。

  

IDENT_CURRENT返回为a生成的最后一个标识值   指定的表或视图。生成的最后一个标识值可以是   任何会议和任何范围。

答案 4 :(得分:2)

您需要通过UNIQUE约束来保证audioformat列的唯一性,并将您的代码放入try/catch

尝试插入。如果失败,则catch,查询新条目,并返回现有ID。

您可以先尝试查询。但是如果有人在你的批处理开始和你插入之间插入,那么DB无论如何都会抛出异常。