我有 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 来完成所有这些操作。
I have 3 tables: audioFormats, videoFormats, and fileInfo.
I have a transaction such that when I insert into the fileInfo table, that insert includes an FK from audioFormats and videoFormats. An insertion into the latter tables takes place if the audio format or video format are not already in those tables, then the generated (or existing) ID value is inserted into fileInfo.
How do I efficiently insert a value only if that value does not exist, but get the ID of the value whether it already exists or was freshly inserted using only SQL (and perhaps a transaction).
I can insert a value if it does not already exist:
INSERT INTO audioformats (audioformat)
VALUES(@format)
WHERE NOT EXISTS (SELECT 1 FROM audioformats WHERE audioformat = @format)
I can get the inserted ID from an insertion:
INSERT INTO audioFormats (audioFormat)
VALUES ('Test')
SET @audioFormatId = SCOPE_IDENTITY()
SCOPE_IDENTITY won't give me an ID value if no insertion took place.
I can execute a scalar query to get the identity after a possible insertion, but it seems like I should be able to do all of this with at most one SELECT and INSERT.
发布评论
评论(5)
您可以使用 IF 语句来执行此操作
,也可以像这样执行:
You can use an IF statement to do this
or you could do it like this:
我将一个答案标记为正确,因为它与我最终的 SQL 最相似,但它并没有真正满足最多使用一次查询和一次插入的原始要求。以下是我最终使用的:
当大多数对查询的调用实际上执行插入时,Hogan 的答案可能会更快,因为 IF NOT EXISTS 查询比实际执行的查询更快返回行。
在大多数情况下值已经存在的情况下,我的可能会更快,因为这样只会执行一个查询(并且不会执行 IF NOT EXISTS 查询)。我怀疑空检查是微不足道的。
I marked an answer as correct because it was the most similar to my final SQL, but it did not really fulfill the original requirement of using at most one query and one insert. The following does, and is what I ended up using:
Hogan's answer will probably be faster when most calls to the query do in fact perform an insertion because an IF NOT EXISTS query is faster than one that actually does return rows.
Mine will probably be faster in cases where the value already exists most of the time because then exactly one query (and no IF NOT EXISTS query) will be made. I suspect the null check is trivial.
我认为你可以使用 MERGE 来实现这一点。
这为您提供了无交易的解决方案。一些聪明的火花可能能够使用
output
子句来获取目标 id 来改进这一点,但下面的方法就可以正常工作。我在下面添加了 StackOverflow 查询测试器的链接。
在此处运行此查询:查询示例的 StackOverflow 链接
I think you can use
MERGE
for this.This gives you a transactionless solution. Some bright spark might be able to improve this using the
output
clause to get the target id, but below will work just fine.I've added a link to the StackOverflow query tester below.
Run this query here: Query StackOverflow link for sample
如果audioFormats表具有自动增量
IDENTITY(1,1)
PK,您可以通过简单的选择来获取刚刚插入的ID:编辑:
正如评论中提到的,这种方法适用于只有一个查询插入表。
否则,您可以查看 IDENT_CURRENT('table_name') 函数。
If audioFormats table has autoincrement
IDENTITY(1,1)
PK you can get just inserted ID by simple select:EDIT:
As was mentioned in comment this approach is applicable when only one query inserting into a table.
Otherwise you can take a look at the IDENT_CURRENT('table_name') function.
您需要通过 audioformat 列是唯一的>UNIQUE 约束,并将代码放入 尝试/捕获。
尝试插入。如果失败,则捕获,查询新条目,并返回现有 ID。
你可以先尝试查询一下。但是,如果有人在批处理开始和插入之间插入,数据库无论如何都会抛出异常。
You'll need to guarantee your
audioformat
column is unique via a UNIQUE constraint, and put your code in a try/catch.Try to insert. If it fails, then catch, query for the new entry, and return the existing ID.
You could try querying first. But if someone inserts between the start of your batch and when you insert, the DB will throw an exception anyhow.