回答
你不說什麼版本的SQL Server。如果SQL Server 2008中您可以使用MERGE
注:這是通常的使用合併爲一的Upsert這就是我本來以爲這個問題是問,但它是有效的,而不WHEN MATCHED
條款,只是用WHEN NOT MATCHED
子句,以便不工作對於這種情況也。使用示例。
CREATE TABLE #A(
[id] [int] NOT NULL PRIMARY KEY CLUSTERED,
[C] [varchar](200) NOT NULL)
MERGE #A AS target
USING (SELECT 3, 'C') AS source (id, C)
ON (target.id = source.id)
/*Uncomment for Upsert Semantics
WHEN MATCHED THEN
UPDATE SET C = source.C */
WHEN NOT MATCHED THEN
INSERT (id, C)
VALUES (source.id, source.C);
在執行方面花費兩個看時的插入是必須要做的大致相等......
Link to plan images for first run
但在沒有插入要做馬修第二輪答案看起來成本較低。我不確定是否有改善這種情況的方法。
Link to plan images for second run
測試腳本
select *
into #testtable
from master.dbo.spt_values
CREATE UNIQUE CLUSTERED INDEX [ix] ON #testtable([type] ASC,[number] ASC,[name] ASC)
declare @name nvarchar(35)= 'zzz'
declare @number int = 50
declare @type nchar(3) = 'A'
declare @low int
declare @high int
declare @status int = 0;
MERGE #testtable AS target
USING (SELECT @name, @number, @type, @low, @high, @status) AS source (name, number, [type], low, high, [status])
ON (target.[type] = source.[type] AND target.[number] = source.[number] and target.[name] = source.[name])
WHEN NOT MATCHED THEN
INSERT (name, number, [type], low, high, [status])
VALUES (source.name, source.number, source.[type], source.low, source.high, source.[status]);
set @name = 'yyy'
IF NOT EXISTS
(SELECT *
FROM #testtable
WHERE [type] = @type AND [number] = @number and name = @name)
BEGIN
INSERT INTO #testtable
(name, number, [type], low, high, [status])
VALUES (@name, @number, @type, @low, @high, @status);
END
我實際上不確定我目前使用哪個版本。合併將如何工作? – 2010-07-16 21:14:22
@Mega - 我已經更新了我的答案,舉例說明MERGE如何用於這種情況。我會檢查執行統計數據,看看這兩種方法之間是否有區別。 – 2010-07-16 21:35:03
問題是正確的,而不是性能。 '如果不存在(SELECT ...)INSERT'會在負載下導致重複錯誤,保證。 – 2010-07-16 22:57:54
IF NOT EXISTS
(SELECT {Columns}
FROM {Table}
WHERE {Column1 = SomeValue AND Column2 = SomeOtherVale AND ...})
INSERT INTO {Table} {Values}
-1,因爲這是在高負載下獲得重複錯誤的** sureshot方式。 SELECT和INSERT在不同的時間運行,並且沒有什麼可以阻止兩個併發線程嘗試插入相同的值。正如Martin發佈的MERGE是一個合適的解決方案 – 2010-07-16 22:46:11
總之,你需要保證你提供的能力表中返回一行:
Insert dbo.Table (Col1, Col2, Col3....
Select 'Value1', 'Value2', 'Value3',....
From Information_Schema.Tables
Where Table_Schema = 'dbo'
And Table_Name = 'Table'
And Not Exists (
Select 1
From dbo.Table
Where Col1 = 'Foo'
And Col2 = 'Bar'
And ....
)
我已經看到了這個變化野生以及:
Insert Table (Col1, Col2, Col3....
Select 'Value1', 'Value2', 'Value3'....
From (
Select 1 As Num
) As Z
Where Not Exists (
Select 1
From Table
Where Col1 = Foo
And Col2 = Bar
And ....
)
我必須投票加入CONSTRAINT
。這是最簡單和最健壯的答案。我的意思是,看看其他答案有多複雜,我會說他們很難正確(並保持正確)。
缺點:[1]讀取代碼時,客戶端代碼在捕獲異常時必須知道的唯一性在DB [2]中強制執行時不明顯。換句話說,那個追隨你的人可能會想「這是怎麼回事?」除此之外:我曾經擔心拋出/捕捉異常是一個性能問題,但我做了一些測試(在SQL Server 2005上),但它並不重要。
- 1. 僅在記錄不存在的情況下插入值
- 2. 在不存在記錄的情況下用SQL插入多行
- 3. Berkeley DB:在不讀取記錄的情況下鎖定記錄
- 4. 如何僅在SQL Server中不存在記錄的情況下添加記錄?
- 5. 記錄的SqlCommand只有在錯誤W的情況下/ PetaPoco
- 6. 僅在Access 2007中不存在的情況下添加記錄
- 7. 只有1條記錄正在插入
- 8. 只有插入MySQL記錄,如果確切的不存在
- 9. SQL查詢 - 插入但只有當記錄不存在時?
- 10. (MYSQL)如何插入記錄只有當它不存在於表
- 11. 如果記錄不存在,插入新記錄,如果記錄存在,則重複記錄
- 12. 只有在不存在的情況下插入MYSQL
- 13. 在插入新記錄之前檢查記錄的存在
- 14. 在不改變現有代碼的情況下記錄異常
- 15. SQL插入記錄如果不存在
- 16. 在沒有先查詢的情況下插入或更新記錄?
- 17. 如何在不使用mysql事件的情況下每年插入新記錄
- 18. 如何只向SQlite插入記錄並忽略已存在的記錄?
- 19. 新記錄插入到數據庫表在我的情況
- 20. MYSQL:插入記錄,如果它已經存在更新記錄
- 21. 如何在沒有複選框的情況下在網格中標記記錄?
- 22. 如何在沒有Foundation的情況下記錄空行?
- 23. 在沒有先查詢的情況下更新記錄?
- 24. 如何在div下插入記錄?
- 25. 插入記錄
- 26. Rails 5在子創建時生成父記錄,只有在不存在的情況下
- 27. 如何在不看{{}的情況下記錄字典?
- 28. 如何在不更改rowversion的情況下更新記錄
- 29. Hibernate/SQL在不返回關聯的情況下檢索記錄
- 30. 如何在不污染方法的情況下記錄日誌?
您是否考慮添加唯一性約束? – bmm6o 2010-07-16 23:09:04