2015-11-19 23 views
0

我有一個DTS包計劃,將文件ODBC數據同步到我的SQL數據庫。它將數據存儲到臨時表中,然後處理信息。它一直以INSERT方式運行,而不是在運行,但現在將其更改爲更新已更改的行。您可以幫助您制定一個策略來刪除已更改的記錄,以便重新插入行或更新行。我嘗試在SELECT * FROM中包裝EXCEPT,但查詢運行了30多秒,EXCEPT本身需要MS。 DELETE FROM除了對EXCEPT工作嗎?有30多列,所以如果我可以刪除並重新插入,寫出更新看起來很長。SQL除了和更新數據

CI =臨時表,CI_Item =目標存儲表。 CI可能具有不存在於CI_Item表中的新行。

這爲我提供了一個結果集的數據進行更新

SELECT * FROM CI WHERE ItemCode IN (SELECT ItemCode FROM CI_Item) 
EXCEPT 
SELECT * FROM CI_Item 

這是我目前簡單的插入常規

PRINT 'Updating CI Item Table...' 
INSERT INTO CI_Item 
SELECT * FROM CI 
WHERE ItemCode NOT IN(SELECT ItemCode FROM CI_Item) 
SET @RecordCount = @@ROWCOUNT 

DELETE FROM CI 
PRINT 'Updated CI Item Table (' + cast(@RecordCount as varchar) + ' records)' 
+1

你看過['MERGE'](https://msdn.microsoft.com/en-us/library/bb510625.aspx)語句嗎?提示:使用合適的軟件(MySQL,Oracle,DB2,...)和版本(例如, '的SQL服務器2014'。語法和功能的差異往往會影響答案。 – HABO

+0

是的,它被標記爲sql-server,它表示所有版本;)我使用2008(100),但是這個數據庫是2000(80)兼容性。如果我能夠開始,我可以處理語法變體。我確實考慮過合併,但是SO的反饋並不積極。 – AdamRoof

回答

0

這是我想出了。我無法做DELETE WHERE EXISTS(SELECT * EXCEPT SELECT *),因爲它只刪除了所有行。因此,我不得不做一個報表隻影響那些從返回EXCEPT

--Common Information (Part Number Detail) 
PRINT 'Updating CI Item Table...' 

--Remove Any Records With Updated Data 
;WITH RecordsWithUpdates AS 
(
    SELECT * FROM CI WHERE ItemCode IN (SELECT ItemCode FROM CI_Item) 
    EXCEPT 
    SELECT * FROM CI_Item 
) 
DELETE FROM CI_Item WHERE ItemCode IN (SELECT ItemCode FROM RecordsWithUpdates) 
SELECT @RecordCount = @@ROWCOUNT 

PRINT '-- > CI_Item Table Removing ' + cast(@RecordCount as varchar) + ' Updated Records' 

--Insert Any New Records Including Updated Rows 
INSERT INTO CI_Item 
SELECT * FROM CI 
WHERE ItemCode NOT IN(SELECT ItemCode FROM CI_Item) 
SET @RecordCount = @@ROWCOUNT 

DELETE FROM CI 
PRINT 'Updated CI Item Table (' + cast(@RecordCount as varchar) + ' records)' 
0

SQL Server的「集合論運營商」,UNION (ALL)EXCEPTINTERSECT是不是你嘗試做真正的最佳。在某些情況下,它們非常棒,尤其是特別的數據比較和分析,但聽起來你正在寫一些將被重複使用的東西,而且性能對你來說很重要。

EXCEPT的替代方法是通過在右表中的適當(不可爲空)列中查找null值來執行左連接並測試連接未成功的位置。

像這樣的東西(我嘲笑了一些#tables大致測試,因此可以看作是一個模板):

-- Equivalent to the EXCEPT: 
select  C.* 
from  #CI   C 
left join #CI_Item T on C.ItemCode=T.ItemCode 
where  T.ItemCode is null 

-- Alternative way to delete: 
;with cteChangedRows as (
    select  C.* 
    from  #CI   C 
    left join #CI_Item T on C.ItemCode=T.ItemCode 
    where  T.ItemCode is null 
    ) 
delete  T 
from  #CI_Item  T 
inner join cteChangedRows C on T.ItemCode=C.ItemCode 

-- And insert: 
insert into #CI_Item 

select  C.* 
from  #CI   C 
left join #CI_Item T on C.ItemCode=T.ItemCode 
where  T.ItemCode is null 

這很可能在更大的數據集執行好得多。與SQL一樣,YMMV。

編輯:

如果您需要在加入相當於EXCEPT佔多列,你會想要做這樣的事情:

select  C.* 
from  #CI   C 
left join #CI_Item T on C.ItemCode=T.ItemCode 
          and C.Column2=T.Column2 
          and C.Column3=T.Column3 
where  T.ItemCode is null 

如果ItemCode中的任何一個,Column2Column3CT之間不匹配,則所有T列將爲null(這就是左連接的工作方式),因此where子句將帶回這些行。這項工作提供T.ItemCode實際上從來沒有nullCI_Item,這就是爲什麼我說上面你必須選擇一個不可空列在where條款中使用。

這種方法顯然比EXCEPT方式輸入更多的文字,如果你有很多列,這就是爲什麼我說EXCEPT是偉大的臨時的東西。然而,對於任何你會寫一次並且運行很多次的東西,這絕對不是一種威懾。

+0

我欣賞信息和解釋,但是我只是運行了左連接和EXCEPT,並且只有在任何列更改了數據時才返回行。我將不得不在你的左連接中的每一列上執行OR操作? – AdamRoof

+1

@AdamRoof我已經添加了一個例子,你應該如何做到這一點我的答案。這是一個AND而不是一個OR;我試圖解釋爲什麼,但如果不清楚,請說清楚。 –