2010-09-22 68 views
0

我有以下表格:試圖修復SQL查詢兩個表

進入
的EntryID - 詮釋
EntryDate - 日期時間

小時
的EntryID - 詮釋
InHour - datetime
OutHour - datetime

對於在條目表中的每個註冊表,應該有至少一個(可能是許多)登記冊上的小時表中,如下所示:

條目
的EntryID:8
EntryDate:9/9/2010 12點31分25秒

小時
的EntryID:8
InHour:2010年9月9日12點31分25秒
OutHour:2010年9月9日18時21分19秒

現在,這些信息存儲在2個相同的數據庫中,一個在本地機器上,一個在服務器上。我試圖編寫一個查詢,該查詢將刪除已經傳遞給服務器的所有信息,條件是沒有OutHour(null)的註冊表不會被刪除。

我寫了下面的查詢:

DELETE from [dbo].[Entry] 
WHERE [dbo].[Entry].[EntryID] IN (SELECT [EntryID] 
            FROM [LINKEDSERVER].[MYDATABASE].[dbo].[Entry]) 
    AND [dbo].[Entry].[EntryID] IN (SELECT [EntryID] 
            FROM [dbo].[Hour] 
            WHERE [OutHour] IS NOT NULL) 

DELETE from [dbo].[Hour] 
WHERE [dbo].[Hour].[InHour] IN (SELECT [InHour] 
            FROM [LINKEDSERVER].[MYDATABASE].[dbo].[Hour]) 
    AND [dbo].[Hour].[OutHour] IS NOT NULL 

AFAIK,該查詢首先檢查在項目表中,並會刪除已經在服務器上,並沒有具有空相應小時註冊表進行任何登記OutHour。但是今天我發現Entry記錄已被刪除,但相應的Hour不是(它有一個空的OutHour)。

我在做什麼錯?任何幫助表示讚賞。

謝謝!

回答

0

我的第一個建議是把兩個上的EntryID之間的外鍵關係。這將阻止從Entry表中刪除任何刪除操作,而不必先刪除Hour表中的所有實例。

其次,在地方的外鍵,你必須從孩子家長做(又名,開始在層次結構的底部)。這意味着我首先做到這一點:

delete from dbo.Hour where OutHour is not null 
delete e 
from dbo.Entry e 
left outer join dbo.Hour h 
on e.entryid=h.entryid 
where h.entryid is null 
1

什麼問題是你的第二個查詢只使用InHour,而不提及EntryID。此外,您的第一個查詢的條件完全相互獨立,如果您的小時表約束正確(第一列在第二列不爲空時不能爲空),則這可能不成問題,但值得一看。

在關係數據庫中,最好養成用JOIN而不是IN()來思考的習慣。使用IN()通常可以返回與JOIN相同的結果(在NULL處理方面有一些差異),並且通常甚至會得到相同的執行計劃,但它是#1的一種「放鬆」方式,用於考慮不出租的問題本身很好地處理編寫複雜查詢所需的心理空間,並且#2無法一次比較多個值,它只能進行單個比較(至少在SQL Server中,因爲其他一些DBMS可以這樣做)。

讓我重寫你的查詢作爲聯接,也許它會幫助你看到什麼是錯的。

DELETE E 
FROM 
    dbo.Entry E 
    INNER JOIN LINKEDSERVER.MYDATABASE.dbo.Entry L ON E.EntryID = L.EntryID 
    INNER JOIN Hour H ON E.EntryID = H.EntryID 
WHERE 
    H.OutHour IS NOT NULL 

DELETE H 
FROM 
    dbo.Hour H 
    INNER JOIN LINKEDSERVER.MYDATABASE.dbo.Hour L ON H.InHour L.InHour 
WHERE 
    H.OutHour IS NOT NULL 

我建議你在小時表上放置級聯刪除外鍵約束,這樣當你從Entry表中刪除時,子小時行全部消失。這裏仍然存在問題,因爲每個EntryID可能有許多Hour行,並且在語義上最終可能會多次嘗試刪除鏈接服務器上的相同行。

而且,要知道,因爲有時查詢引擎決定在鏈路上拉巨大的行集龐大加入了鏈接的服務器可以體驗性能非常差,甚至整個表。您可以通過分批處理來緩解這種情況,也許首先通過鏈接上的JOIN進行基於JOIN的臨時表選擇,然後以小批量100或1000或5000刪除相應的行(測試是爲了找到正確的尺寸)。最後,如果您確實發現您的查詢不必要地通過鏈接提取大量數據(通過在遠程matchine上運行查詢分析器查看提交哪些實際查詢來確定此情況),那麼戰略性地使用CROSS APPLY可以通過強制一行一行地處理,這在鏈接服務器的情況下,可以是巨大性能改善,儘管如何反直覺是相對於標準和強大的建議從來都行,由行幫助關係數據庫。把它看作是強制「拉伸書籤查找」,而不是「拉伸表掃描」,你會得到一個爲什麼這可以是如此大的幫助的暗示。