2010-07-16 53 views

Trả lời

24

Bạn không nói phiên bản SQL Server nào. Nếu SQL Server 2008 bạn có thể sử dụng MERGE

NB: Thông thường, hãy sử dụng Kết hợp cho Upsert, đó là điều tôi cho là câu hỏi ban đầu nhưng nó hợp lệ mà không có mệnh đề WHEN MATCHED và chỉ với mệnh đề WHEN NOT MATCHED. cho trường hợp này cũng vậy. Sử dụng ví dụ.

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); 

Xét về thực hiện chi phí hai trông tương đương khi Insert là việc phải làm ...

Link to plan images for first run

nhưng trên đường chạy trốn thứ hai khi không có chèn phải làm Matthêu câu trả lời có vẻ thấp hơn chi phí. Tôi không chắc liệu có cách cải thiện điều này không.

Link to plan images for second run

Script Test

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 
+0

Tôi thực sự không chắc chắn mình đang sử dụng phiên bản nào. Hợp nhất sẽ hoạt động như thế nào? –

+0

@Mega - Tôi đã cập nhật câu trả lời của mình với ví dụ về cách 'MERGE' có thể được sử dụng cho trường hợp này. Tôi sẽ kiểm tra số liệu thống kê thực hiện để xem liệu có bất kỳ sự khác biệt nào giữa 2 cách tiếp cận hay không. –

+3

Vấn đề là chính xác, không phải hiệu suất. 'IF NOT EXISTS (SELECT ...) INSERT' sẽ gây ra lỗi trùng lặp dưới tải, được bảo đảm. –

13
IF NOT EXISTS 
    (SELECT {Columns} 
    FROM {Table} 
    WHERE {Column1 = SomeValue AND Column2 = SomeOtherVale AND ...}) 
INSERT INTO {Table} {Values} 
+8

-1 vì đây là cách ** ** sureshot bị lỗi trùng lặp khi tải cao. SELECT và INSERT chạy vào các thời điểm khác nhau và không có gì để ngăn chặn hai luồng đồng thời cố gắng chèn cùng một giá trị. MERGE, như được đăng bởi Martin, là một giải pháp thích hợp –

1

Tóm lại, bạn cần một bảng đảm bảo để cung cấp cho bạn khả năng quay trở lại một dòng:

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 .... 
        ) 

Tôi đã nhìn thấy sự thay đổi này trong tự nhiên:

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 .... 
        ) 
0

Tôi phải bỏ phiếu để thêm CONSTRAINT. Đó là câu trả lời đơn giản và mạnh mẽ nhất. Ý tôi là, nhìn vào những câu trả lời khác phức tạp như thế nào, tôi muốn nói rằng họ sẽ khó hơn nhiều để có được quyền (và giữ đúng).

Những nhược điểm: [1] không rõ ràng khi đọc mã mà tính duy nhất được thực thi trong DB [2] mã máy khách phải biết để bắt ngoại lệ. Nói cách khác, anh chàng đến sau khi bạn có thể tự hỏi "làm thế nào điều này đã bao giờ làm việc?"

Điều đó sang một bên: Tôi đã từng lo lắng rằng việc ném/bắt ngoại lệ là hiệu suất nhưng tôi đã thực hiện một số thử nghiệm (trên SQL Server 2005) và không đáng kể.

Các vấn đề liên quan