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

Cha*_*rns 20 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)
Run Code Online (Sandbox Code Playgroud)

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

INSERT INTO audioFormats (audioFormat)
VALUES ('Test')
SET @audioFormatId = SCOPE_IDENTITY()
Run Code Online (Sandbox Code Playgroud)

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

Hog*_*gan 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
Run Code Online (Sandbox Code Playgroud)

或者你可以这样做:

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
Run Code Online (Sandbox Code Playgroud)


Cha*_*rns 6

我将一个答案标记为正确,因为它与我最终的 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
Run Code Online (Sandbox Code Playgroud)

当对查询的大多数调用实际上执行插入时,Hogan 的回答可能会更快,因为 IF NOT EXISTS 查询比实际返回行的查询快。

在大部分时间该值已经存在的情况下,我的可能会更快,因为这样只会进行一个查询(并且没有 IF NOT EXISTS 查询)。我怀疑空检查是微不足道的。

  • 这与我现在使用的代码完全相同,但我发现在负载下多个存储过程可能同时运行类似代码时出现问题。发生的情况是第一个 IF 语句返回 NULL,但在 INSERT 语句发生之前,另一个存储过程已插入该值。然后我收到有关重复值的错误。 (2认同)