Sql-Server

獲取 SQL Server 數據庫的“切片”:對於所有表,僅獲取連接(直接或間接)特定行的行

  • April 8, 2021

出於審計目的,我試圖獲取數據庫的副本/導出,但僅包括每個表中與某個表中的一小部分行集合相關的行。所以這些行指向的每個表的每一行;每個表中指向這些行的每一行;等等。(在代數術語中,這是這些行相對於外鍵關係的傳遞對稱自反閉包。)

我想知道是否存在某種工具可以做到這一點,或者這是否可以以某種方式編寫腳本。我有大約 400 個表,外鍵網路很緊密,所以我不想手動執行此操作。

您當然可以使用嵌套儲存過程編寫腳本:

  1. 被稱為類似EXEC recursive_shaped_query @StartTable='SomeTable', @KeyColumn='Id', @ValuesSQL='SELECT Id FROM (VALUES (1),(6),(4576),(42)) AS Ids(Id)'
  2. 然後通過 ad-hoc SQL 執行SELECT * FROM SomeTable WHERE Id IN (SELECT Id FROM (VALUES (1),(6),(4576),(42)) AS Ids(Id))
  3. 然後它會通過游標sys.foreign_keys找到任何引用該表的表並…
  4. …對於每個找到的此類表,都稱自己為EXEC recursive_shaped_query @StartTable='ReferencingTable', @KeyColumn='Id', @ValuesSQL='SELECT Id FROM SomeTable WHERE Id IN (SELECT Id FROM (VALUES (1),(6),(4576),(42)) AS Ids(Id))'

當然,會有一些複雜的情況需要考慮:

  • 如果您的資料結構允許循環連結,例如包含狀態機圖的表格,或者兩個實體可能相互引用的位置,您將需要決定該怎麼做,否則這將循環到無窮大(好吧,直到您點擊“過程呼叫嵌套太深”錯誤)。
  • 您可能需要處理作用於多個欄位而不僅僅是一個欄位的外鍵。
  • 如果有用的索引沒有到位,SELECT * FROM t1 WHERE Id IN (SELECT Id FROM t2 WHERE Id IN (SELECT Id FROM Tt3 WHERE ... )))嵌套可能會變得很長,並且是由於表掃描而需要很長時間才能執行的查詢。

其他需要注意的事項:

  • 您可能會發現使用連接而不是子選擇會產生更高效的查詢(儘管我認為查詢規劃器會在優化兩個語法選項以使其等效方面做得不錯)。
  • 您可能更喜歡該過程只是發出所需的臨時 SQL 而不是執行它,因此您可以稍後執行它(並在其他地方再次執行它)。
  • 如果只是發出 ad-hoc SQL 而不執行它,則在 sys.foreign_keys 上的遞歸 CTE 可能比嵌套儲存過程明顯更乾淨 - 實際上這樣做可能會更好:在執行中生成 SQL 然後在一個中執行它去,也許顯式地將數據刪除到臨時表,然後結束目前事務以釋放鎖,然後再將數據推送給讀取器。
  • 這當然是假設您在應該在的任何地方都定義了外鍵。在太多的數據庫中,缺少部分或全部這些約束。

對於我們的系統

$$ Day Job $$我手動創建了一組這樣的查詢來提取給定實體的嵌套數據,因為這些過程對於診斷很有用,但我從來不需要它們來保證嘗試創建生成器或其他自動化解決方案。我一直認為它是一個遊戲項目,但實際上並沒有這樣做。

引用自:https://dba.stackexchange.com/questions/289491