使用 sqlrutils 將 R 程式碼轉換為預存程序
本文描述使用 sqlrutils 封裝,將 R 程式碼轉換成 T-SQL 預存程序的步驟。 為能獲致最佳結果,可能需要部分修改您的程式碼,以確保所有輸入皆能參數化。
步驟 1: 重寫 R 指令碼
為了獲得最佳結果,您應該重寫 R 程式碼,將它封裝為單一函式。
函式所使用的所有變數皆應該定義在函式內,或定義為輸入參數。 請參閱本文的 範例程式碼。
此外,由於 R 函式的輸入參數會成為 SQL 預存程序的輸入參數,因此您必須確定您的輸入和輸出符合下列類型需求:
輸入
輸入參數之間最多只能有一個資料框架。
資料框架內的物件與函式的其他所有輸入參數,皆必須是下列 R 資料類型:
- POSIXct
- NUMERIC
- character
- integer
- 邏輯
- raw
如果輸入類型不是上述類型之一,就必須將其序列化並以 未經處理的形式傳遞給函式。 在此情況下,函式也必須包含可還原序列化輸入項目的程式碼。
輸出
函式可以輸出下列其中一個項目:
- 資料框架,其中包含支援的資料類型。 資料框架中的所有物件都必須使用其中一種支援的資料類型。
- 具名清單,其中包含最多一個資料框架。 清單的所有成員都應該使用其中一種支援的資料類型。
- NULL (如果您的函式未傳回任何結果)
步驟 2: 產生必要的物件
在您的 R 程式碼已清除,而且可以作為單一函式來呼叫之後,您將使用 sqlrutils 套件中的函式,以可傳遞至實際建置預存程序的建構函式形式,來準備輸入和輸出。
sqlrutils 提供可定義輸入資料結構描述和類型,以及定義輸出資料結構描述和類型的函式。 它也包含可將 R 物件轉換成所需輸出類型的函式。 根據您的程式碼所使用的資料類型而定,您可能會進行多個函式呼叫來建立必要的物件。
輸入
如果您的函式接受輸入,則針對每個輸入,呼叫下列函式:
- 如果輸入是資料框架,則為
setInputData
setInputParameter
適用於所有其他輸入類型
當您進行每個函式呼叫時,會建立一個 R 物件,稍後您會將它作為引數傳遞給 StoredProcedure
,以建立完整的預存程序。
輸出
sqlrutils 提供多個函式,可將 R 物件 (例如清單) 轉換成 SQL Server 所需的 data.frame。 如果您的函式會直接輸出資料框架,而不需先將其包裝到清單中,您即可略過這個步驟。 如果您的函數傳回 NULL,您也可以略過轉換此步驟。
轉換清單或從清單中取得特定項目時,請從下列函式中選擇:
- 如果清單中的變數為資料框架,則為
setOutputData
setOutputParameter
適用於清單的其他所有成員
當您進行每個函式呼叫時,會建立一個 R 物件,稍後您會將它作為引數傳遞給 StoredProcedure
,以建立完整的預存程序。
步驟 3: 產生預存程序
當所有輸入和輸出參數都準備就緒時,請呼叫 StoredProcedure
建構函式。
使用量
StoredProcedure (func, spName, ..., filePath = NULL ,dbName = NULL, connectionString = NULL, batchSeparator = "GO")
為了說明,假設您想要使用這些參數來建立名為 sp_rsample 的預存程序:
- 使用現有的函式 foosql。 此函數的基礎是 R 函數 foo 中現有的程式碼,但您重寫了此函數,以滿足本節所述之需求,並將更新的函數命名為 foosql。
- 使用資料框架 queryinput 作為輸入
- 使用 R 變數名稱 (sqloutput) 以輸出形式產生資料框架
- 您想要建立 T-SQL 程式碼作為
C:\Temp
資料夾中的檔案,以便您可以在稍後使用 SQL Server Management Studio 執行它
StoredProcedure (foosql, sp_rsample, queryinput, sqloutput, filePath = "C:\\Temp")
注意
由於您是將檔案寫入檔案系統,因此可以省略定義資料庫連線的引數。
函式的輸出是 T-SQL 預存程序,可以在 SQL Server 2016 (需要 R 服務) 或 SQL Server 2017 (需要機器學習服務搭配 R) 的執行個體上執行。
如需其他範例,請參閱套件說明,方法是從 R 環境呼叫 help(StoredProcedure)
。
步驟 4: 註冊並執行預存程序
有兩種方式可讓您執行預存程序:
- 從支援 SQL Server 2016 或 SQL Server 2017 執行個體連線的任何用戶端使用 T-SQL
- 從 R 環境
這兩種方法都需要在您要使用預存程序的資料庫中註冊預存程序。
註冊預存程序
您可以使用 R 來註冊預存程序,也可以在 T-SQL 中執行 CREATE PROCEDURE 陳述式。
使用 T-SQL。 如果您更熟悉 T-SQL,請開啟 SQL Server Management Studio (或任何其他可執行 SQL DDL 命令的用戶端),然後使用
StoredProcedure
函式準備的程式碼來執行 CREATE PROCEDURE 陳述式。使用 R。在您仍在 R 環境中時,可以使用
registerStoredProcedure
sqlrutils中的 函式向資料庫註冊預存程序。例如,您可以藉由進行此 R 呼叫,在 sqlConnStr 中定義的執行個體和資料庫中註冊預存程序 sp_rsample:
registerStoredProcedure(sp_rsample, sqlConnStr)
重要
無論您使用的是 R 或 SQL,都必須使用有權限建立新資料庫物件的帳戶來執行陳述式。
使用 SQL 執行
建立預存程序之後,請使用支援 T-SQL 的任何用戶端開啟 SQL 資料庫的連線,並傳遞預存程序所需之任何參數的值。
使用 R 執行
如果您想要從 R 程式碼執行預存程序,而不是從 SQL Server,則需要一些額外的準備工作。 例如,如果預存程序需要輸入值,則必須在執行函式之前設定那些輸入參數,然後將那些物件傳遞到 R 程式碼中的預存程序。
呼叫已備妥之 SQL 預存程序的整體程序如下:
- 呼叫
getInputParameters
以取得輸入參數物件的清單。 - 針對每個輸入參數,定義
$query
或設定$value
。 - 使用
executeStoredProcedure
以從 R 開發環境執行預存程序,同時傳遞您所設定的輸入參數物件清單。
範例
此範例會顯示 R 指令碼的前後版本,該指令碼從 SQL Server 資料庫取得資料、對資料執行一些轉換,然後將其保存到不同的資料庫中。
這個簡單的範例僅用來說明您可以如何重新排列 R 程式碼,使它更容易轉換為預存程序。
程式碼準備之前
sqlConnFrom <- "Driver={ODBC Driver 13 for SQL Server};Server=MyServer01;Database=AirlineSrc;Trusted_Connection=Yes;"
sqlConnTo <- "Driver={ODBC Driver 13 for SQL Server};Server=MyServer01;Database=AirlineTest;Trusted_Connection=Yes;"
sqlQueryAirline <- "SELECT TOP 10000 ArrDelay, CRSDepTime, DayOfWeek FROM [AirlineDemoSmall]"
dsSqlFrom <- RxSqlServerData(sqlQuery = sqlQueryAirline, connectionString = sqlConnFrom)
dsSqlTo <- RxSqlServerData(table = "cleanData", connectionString = sqlConnTo)
xFunc <- function(data) {
data$CRSDepHour <- as.integer(trunc(data$CRSDepTime))
return(data)
}
xVars <- c("CRSDepTime")
sqlCompute <- RxInSqlServer(numTasks = 4, connectionString = sqlConnTo)
rxOpen(dsSqlFrom)
rxOpen(dsSqlTo)
if (rxSqlServerTableExists("cleanData", connectionString = sqlConnTo)) {
rxSqlServerDropTable("cleanData")}
rxDataStep(inData = dsSqlFrom,
outFile = dsSqlTo,
transformFunc = xFunc,
transformVars = xVars,
overwrite = TRUE)
注意
當您使用 ODBC 連線,而不是叫用 RxSqlServerData 函式的話,則必須使用 rxOpen 開啟連接,才能在資料庫上執行作業。
程式碼準備之後
在更新的版本中,第一行會定義函式名稱。 所有來自原始 R 方案的其他程式碼都會變成該函式的一部分。
myetl1function <- function() {
sqlConnFrom <- "Driver={ODBC Driver 13 for SQL Server};Server=MyServer01;Database=Airline01;Trusted_Connection=Yes;"
sqlConnTo <- "Driver={ODBC Driver 13 for SQL Server};Server=MyServer02;Database=Airline02;Trusted_Connection=Yes;"
sqlQueryAirline <- "SELECT TOP 10000 ArrDelay, CRSDepTime, DayOfWeek FROM [AirlineDemoSmall]"
dsSqlFrom <- RxSqlServerData(sqlQuery = sqlQueryAirline, connectionString = sqlConnFrom)
dsSqlTo <- RxSqlServerData(table = "cleanData", connectionString = sqlConnTo)
xFunc <- function(data) {
data$CRSDepHour <- as.integer(trunc(data$CRSDepTime))
return(data)}
xVars <- c("CRSDepTime")
sqlCompute <- RxInSqlServer(numTasks = 4, connectionString = sqlConnTo)
if (rxSqlServerTableExists("cleanData", connectionString = sqlConnTo)) {rxSqlServerDropTable("cleanData")}
rxDataStep(inData = dsSqlFrom,
outFile = dsSqlTo,
transformFunc = xFunc,
transformVars = xVars,
overwrite = TRUE)
return(NULL)
}
注意
雖然您不需要明確地在程式碼中開啟 ODBC 連接,但使用 sqlrutils時仍需要 ODBC 連接。