本文介绍使用 sqlrutils 包将 R 代码转换为作为 T-SQL 存储过程运行的步骤。 为了获得最佳结果,可能需要对代码进行一些修改,以确保可以参数化所有输入。
步骤 1。 重写 R 脚本
为了获得最佳结果,应重写 R 代码以将其封装为单个函数。
函数使用的所有变量都应在函数内定义,或应定义为输入参数。 请参阅本文中的 示例代码 。
此外,由于 R 函数的输入参数将成为 SQL 存储过程的输入参数,因此必须确保输入和输出符合以下类型要求:
输入
在输入参数中,最多可以有一个数据帧。
数据帧内的对象以及函数的所有其他输入参数必须具有以下 R 数据类型:
- POSIXct
- numeric
- 字符
- 整数
- 逻辑
- raw
如果输入类型不是上述类型之一,则需要序列化并作为 原始传入函数。 在这种情况下,该函数还必须包含用于反序列化输入的代码。
Outputs
该函数可以输出以下项之一:
- 包含支持的数据类型的数据帧。 数据帧中的所有对象都必须使用受支持的数据类型之一。
- 一个命名列表,最多包含一个数据帧。 列表的所有成员都应使用受支持的数据类型之一。
- 如果函数未返回任何结果,则为 NULL
步骤 2。 生成所需的对象
清理 R 代码并可以调用为单个函数后,将使用 sqlrutils 包中的函数准备表单中的输入和输出,该表单可以传递给实际生成存储过程的构造函数。
sqlrutils 提供定义输入数据架构和类型的函数,以及定义输出数据架构和类型。 它还包括可将 R 对象转换为所需输出类型的函数。 可以进行多个函数调用来创建所需的对象,具体取决于代码使用的数据类型。
输入
如果您的函数接受输入参数,请对每个输入调用以下函数:
-
setInputData如果输入是数据框 -
setInputParameter适用于所有其他输入类型
每次调用函数时,都会创建一个 R 对象,稍后将作为参数传递给该对象 StoredProcedure,以创建完整的存储过程。
Outputs
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")
注意
由于将文件写入文件系统,因此可以省略定义数据库连接的参数。
函数的输出是在 SQL Server 2016(需要 R 服务)或 SQL Server 2017 实例上执行的 T-SQL 存储过程(需要使用 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 环境中,可以使用
registerStoredProceduresqlrutils 中的函数向数据库注册存储过程。例如,可以通过进行以下 R 调用,在 sqlConnStr 中定义的实例和数据库中注册存储过程sp_rsample:
registerStoredProcedure(sp_rsample, sqlConnStr)
Important
无论使用 R 还是 SQL,都必须使用有权创建新数据库对象的帐户运行该语句。
使用 SQL 运行
创建存储过程后,使用支持 T-SQL 的任何客户端打开与 SQL 数据库的连接,并为存储过程所需的任何参数传递值。
使用 R 运行
如果要从 R 代码执行存储过程,而不是从SQL Server执行存储过程,则需要进行一些额外的准备。 例如,如果存储过程需要输入值,则必须在执行函数之前设置这些输入参数,然后将这些对象传递到 R 代码中的存储过程。
调用准备的 SQL 存储过程的整个过程如下所示:
- 调用
getInputParameters以获取输入参数对象的列表。 - 为每个输入参数定义一个
$query,或设置一个$value。 - 使用
executeStoredProcedure在 R 开发环境中执行存储过程,并传递你设置的输入参数对象列表。
例
此示例演示从SQL Server数据库获取数据的 R 脚本前后,对数据执行一些转换,并将其保存到其他数据库。
此简单示例仅用于演示如何重新排列 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 连接。