2011-06-04 66 views
3

我需要對我的數據庫中的所有具有相同結構的很多表使用相同的存儲過程。這是從客戶加載的數據,只有一個表/客戶,數據需要計算/檢查才能加載到DataWarehouse中。創建可以使用不同表格的存儲過程

到目前爲止,這些都是我找到的選項和問題,我正在尋找更好的模式/方法。

  1. 創建指向 表我想處理來看,SP的 然後再跟這個觀點。這工作 好(特別是一旦我制定了 如何創建'自動'視圖' 根據他們的專欄)。但 視圖一次只能與一個表 一起使用,一次強制系統與一個客戶打交道 。

  2. 使用每個SP中的動態SQL - 使得SP的更難 讀/調試,併爲那些原因一直 被排除

  3. 跨越 所有表創建一個分區視圖,然後使用 paramatised表函數返回 只是我們感興趣的數據 - 啊,但我就不能更新數據 作爲函數返回一個表, 只能用於選擇

  4. 功能 (不能做)內使用動態SQL創建視圖 (也不能這樣做)......給 了
  5. 內SP創建臨時表 超過使用 動態SQL目標表,但後來臨時表 只存在於運行 動態SQL不是「父」 是正在運行的SP會話的會話... 放棄
  6. 創建一個全局臨時表使用 動態SQL來避免範圍問題 爲5,然後再次運行SP t全球臨時表 。仍遇到 單一客戶問題。
  7. 一個 事務中創建視圖1,然後運行所有SP ,然後提交 - 工作正常,一個 用戶,但現在任何人都阻擋 試圖創建 同名
  8. 的新觀點
  9. 使用臨時視圖...不能在 T /的Sql
  10. 把所有的代碼爲淨 - 但 我們有環境問題,其中 TSQL是非常容易的主機/運行

我知道我不是唯一一個有這個問題的人,請你幫忙解決問題,請幫忙。

+0

那麼,MrTelly,你只接受了你在這裏問過的50個問題中的一半的答案,所以我對繼續嘗試幫助你的興趣水平相當低。 – DOK 2011-06-04 11:35:04

+0

您是否需要檢查每個表格中的整個數據還是僅檢查一些行?這個過程是否在某一時刻運行?如果是這樣,批處理將處理相同的表/行? – Rodrigo 2011-06-07 02:32:01

+0

我明白你的觀點,@MrTelly。但請理解,那些試圖建立自己聲譽的人可能會花費大量時間和思想來研究和迴應像你這樣一個相當具有挑戰性的問題,因爲他們的努力獲得獎勵的可能性似乎很低。即使現在有了獎勵,你會有什麼獎勵嗎?我只是想幫助你在這裏擺脫現實。 – DOK 2011-06-07 08:21:20

回答

11

也許你的做法是錯誤的,我會深入詳細的一段時間,但它似乎是你的問題可以通過SSIS

來解決 - 更新答案

首先,大圖片:

動態處理表的最經濟實惠的方法是使用腳本而不是存儲過程。如果你想隨機選擇表訪問,你肯定不會使用存儲過程的任何性能優勢,即執行計劃。 SQL腳本可以很容易地升級,在運行時使用佔位符指向一個表並在執行前替換它。

該腳本可以從文件系統,變量,表格中的文本列等加載。加載過程包括將腳本內容讀取到字符串變量。這一步發生一次。

下一步是準備階段。該步驟將針對每個要處理的表執行。此步驟的主要業務是用正在處理的當前表替換表佔位符。還可以設置參數值,如可能需要傳遞到您已寫入的sp中的任何參數。

最後一步是腳本的執行。由於已經加載到一個變量中,並且佔位符被設置爲當前表名,所以可以安全地調用ExecuteSQLTask並將sql變量作爲輸入。這個過程當然會發生在你想要處理的每個表上。

好的。現在讓我們看看這是行動。

這是一個樣的數據庫模型:

CREATE TABLE [dbo].[t_n](
    [id] [int] IDENTITY(1,1) NOT NULL, 
    [name] [varchar](50) NOT NULL, 
    [start] [datetime] NULL, 
    CONSTRAINT [PK_t_n] PRIMARY KEY CLUSTERED ([id] ASC) 
) ON [PRIMARY] 

其中t_n代表任意表(T_1,T_2,T_3等)。

這是當前的存儲過程:

CREATE PROCEDURE SpProcessT_n 
AS 
BEGIN 
    SET NOCOUNT ON; 
    SELECT * FROM [t1]; 
END 
GO 

現在,轉換此存儲過程SQL腳本,放置一個佔位符,而不是表名的

SET NOCOUNT ON; 
    SELECT * FROM [$table_name]; 

我選擇把它保存在文件系統中的.sql文件以儘可能簡化POC。

接下來,創建一個SSIS包這樣的:

Basic SSIS Package

這些都是我選擇設置循環設置: enter image description here

這是你可以分配表的方式名稱改爲正確調用_table_name_ enter image description here

這是腳本任務的設置,在這裏您可以找到該變量_table_name_已只讀訪問,而一個叫做SQLEXEC新的變量讀/寫訪問:

enter image description here

,這是它的主要功能:

public void Main() 
    { 
     String Table_Name = Dts.Variables["table_name"].Value.ToString(); 
     String SqlScript; 
     Regex reg = new Regex(@"\$table_name", RegexOptions.Compiled); 
     using (var f = File.OpenText(@"c:\sqlscript.sql")) { 
      SqlScript = f.ReadToEnd(); 
      f.Close(); 
     } 
     SqlScript = reg.Replace(SqlScript, Table_Name); 
     Dts.Variables["SqlExec"].Value = SqlScript; 
     Dts.TaskResult = (int)ScriptResults.Success; 
    } 

可以注意到DTS變量SqlExec包含將被執行的sql腳本。現在,你可以在你的ExecuteSqlTask​​設置以下選項:

enter image description here

在MSSQL 2008年試驗成功,如果你把一個插入腳本文件裏面,你會發現每個表中新行。

希望這會有所幫助!

+0

我很感興趣,你可以填寫你的答案,所以我知道這個方法是什麼 – MrTelly 2011-06-08 04:15:02

+0

我忙於工作,沒有時間。在週末也許;) – Rodrigo 2011-06-10 16:09:05

+0

好的,這是你的答案! – Rodrigo 2011-06-13 09:33:49

0

我相當肯定,解決這個問題的標準方法是在每個sp(您的選項2)中使用動態SQL,這已經被排除了。

您的目標是製作通用的多表SQL。我不明白你在不犧牲效率和可讀性的情況下如何實現這一目標。

1

編寫包含表名的分區視圖?

SELECT 'TableName', t.* FROM TableName t 
UNION ALL 
SELECT 'TableName2', t.* FROM TableName2 t 

然後寫的,而不是它使用動態SQL編寫觸發單(涉及使用動態SQL的少的測試,因爲你只寫了簡單的CRUD操作一次,我倒是覺得所有表)

+0

我可以用分區視圖和where子句模仿這種方法,但是當我有120多個表並且知道我只更新其中的一個時,它的效率非常低效 – MrTelly 2011-06-07 03:49:28

+0

啊,是的,我不記得T-SQL贏得了'如果該值是一個參數,則優化該值。 – 2011-06-07 04:10:30

2

如果您的應用程序能夠承受延遲一天的截止日期,那麼您可以每晚安排一份計劃作業來運行SSIS軟件包,該軟件包可將所有150多張表格合併成一張巨大的表格。由於針對該巨大表格的查詢結果的新鮮度將晚於1日,因此該解決方案將不包括最近加載的任何行。

你實際上可以計時運行這個軟件包。如果它仍然非常快,例如在30分鐘內說,那麼你可以打賭每隔幾個小時運行一次,比如在工作日開始,午餐休息和一天結束時。通過這種方式,您可以使用幾乎全新的數據進行查詢。

+0

您可以使用此SSIS工具來執行行校驗和。因此,每次都要重新銷燬並重新構建大量數據,只有不同的行會更新,http://www.sqlis.com/sqlis/post/Checksum-Transformation.aspx。 – 2011-06-13 08:30:43

1

我不會這樣做與SQL。你所描述的聽起來像傳統的ETL情況。

因爲所有客戶表都是相同的,所以我會在數據倉庫中創建一個表,其中包含客戶表中的所有列,代理鍵列和類型標識。您可以選擇在此處創建一個「暫存」表,該表只會在ETL過程中擁有數據,或者僅在一個「實時」表上工作。我會創建登臺表。

然後在SSIS包(不用擔心,您仍然可以從SQL Server代理安排,它並沒有完全離開數據庫服務器),啓動ETL過程...

E(xtract):將數據從源複製到數據倉庫中的登臺表中。你很可能想在foreach循環中使用一個子包,並且改變你想從外部存儲處理的表的名字(大多數人會說把它放在倉庫裏,但它取決於你)。

牛逼(ransform):運行你在談論的計算/檢查,但這樣做對整個集...

大號(OAD):它複製到你的真實數據中倉庫。

有幾件事我不會做。 1.修改源表中的數據。 2.嘗試在t-sql中執行此操作。它只是不是tsql擅長的。

如果您需要關於此方法的更多詳細信息,我可能會問一些商業智能標籤的問題。我會在接下來的一週左右旅行,但如果你需要我,我會試着看看評論以澄清任何事情。