使用 R RODBC 参数化 SQL 查询

Posted

技术标签:

【中文标题】使用 R RODBC 参数化 SQL 查询【英文标题】:Parameterize SQL Queries using R RODBC 【发布时间】:2018-06-08 12:15:11 【问题描述】:

我有一个相当简单的问题。

每天,我使用 RODBC 包在 R 中执行数据分析。我使用 SQL 将它连接到我们的数据仓库并将其移动到 R 环境中

dbhandle <- odbcDriverConnect('driver=SQL Server;server=SQLSERVER;database=MYDATABASE;trusted_connection=true')

degrees <- sqlQuery(dbhandle, "select Inst, ID, DegreeDate, Degree from DEGREE where FY = ('2015') group by Inst, ID, DegreeDate, Degree order by Inst, ID, DegreeDate, Degree", as.is=TRUE)

您知道如何在 MS Access 中弹出一个窗口,例如询问您什么 FY?您输入 2015 年,您将获得该财政年度的所有递减。

有没有办法在 R 中做到这一点?我在 Stack Overflow 上看到的参数查询问题涉及更改 SQL 数据库中的数据,我对此不感兴趣。我只想设置一些非常基本的限制,以便我可以重新运行代码。

有些人可能想知道“为什么不能将 5 更改为 6?”这是一个公平的观点,但我担心,对于更复杂的查询,用户可能会错过 SQL 查询中将 5 更改为 6 的部分,这会弄乱分析或减慢分析速度。

谢谢! 沃克

【问题讨论】:

如果RODBC 还不支持这个,那么我猜你可能必须自己实现部分或全部。 【参考方案1】:

Input Parameter pop-up box 是严格意义上的 MSAccess.exe GUI 功能。如果通过 ODBC 将 MS Access 作为后端数据库(MS Office 软件之外)运行,使用未知参数的查询将失败,并且在进行 ODBC 调用的脚本上会出现错误。

因此,您需要使用 GWidgets 或 Shiny 等库在 R 中创建类似的 GUI 弹出框,然后将用户的输入值传递给查询。并使用实际的parameterization using RODBCext(RODBC 的扩展)执行此操作,以防恶意用户运行 SQL 注入并可能擦除数据或破坏您的 SQL Server 数据库。

下面是一个使用GWidgets2 和财政年度组合框的示例(下面的屏幕截图)。

library(RDOBC)
library(RODBCext)
library(gWidgets2)
library(gWidgets2tcltk)

options(guiToolkit="tcltk")

GUI功能 (预先创建R和SQLServer gif图像)

mainWindow <- function()

  # TOP OF WINDOW
  win <- gWidgets2::gwindow("Fiscal Year User Input", height = 200, width = 300)

  tbl <- glayout(cont=win, spacing = 8, expand=TRUE)

  # IMAGE
  tbl[1,1] <- gimage(filename = "RSQLServerGUI.gif", 
                     dirname = "/path/to/gif/image", container = tbl)
  # LABEL
  tbl[2,1] <- glabel("Fiscal Year Selection:                      ", container = tbl)
  font(tbl[2,1]) <- list(size=12, family="Arial")

  # COMBO BOX OF FISCAL YEARS
  tbl[3,1, expand=TRUE] <- fiscal_year_cbo <- gcombobox(as.character(c(2012:2018)), 
                                                        selected = 1, editable = TRUE, 
                                                        index=TRUE, container = tbl)
  font(tbl[3,1]) <- list(size=16, family="Arial")

  # COMBO BOX CHANGE FUNCTION (2012 - 2018)
  addHandlerChanged(fiscal_year_cbo, handler=function(...)  
    fiscal_year_value <- svalue(fiscal_year_cbo)           # GET USER SELECTED VALUE
    gmessage(paste("You selected FY:", fiscal_year_value))

    degrees <- getDegreesData(fiscal_year_value)           # GET DATABASE DATA 
    dispose(win)                                           # CLOSE WINDOW
  )


查询函数 (在上面的组合框更改处理程序中调用)

getDegreesData <- function(fy_param) 

    dbhandle <- odbcDriverConnect('driver=SQL Server;server=SQLSERVER;database=MYDATABASE;trusted_connection=true')

    # PREPARED STATEMENT (NO CONCATENATED DATA)
    strSQL <- "select Inst, ID, DegreeDate, Degree 
               from DEGREE 
               where FY = ?
               group by Inst, ID, DegreeDate, Degree 
               order by Inst, ID, DegreeDate, Degree"

    # PASS PARAMETER TO RETURN DATAFRAME
    sql_df <- sqlExecute(dbhandle, strSQL, fy_param, fetch=TRUE)
    odbcClose(dbHandle)

    return(sql_df)

运行图形界面

m <- mainWindow()

截图

【讨论】:

【参考方案2】:

您可以在开始时创建一个输入变量并将其传递给您的查询。 例如:

# Change your FY here
input_FY <- 2016

dbhandle <- odbcDriverConnect('driver=SQL Server;server=SQLSERVER;database=MYDATABASE;trusted_connection=true')

degrees <- sqlQuery(dbhandle, paste0("
select Inst, ID, DegreeDate, Degree 
from DEGREE 
where FY = ('", input_FY, "') 
group by Inst, ID, DegreeDate, Degree 
order by Inst, ID, DegreeDate, Degree"), 
as.is=TRUE)

因此,对于任何复杂的查询,您仍然可以传递相同的 input_FY 变量或您在代码开头声明的任何其他变量,以便快速/轻松地更新。

【讨论】:

谢谢!但是我没有从中得到数据框我做错了什么吗?它变成了一个字符 degrees 返回什么?它应该返回一个数据框,我认为它返回了一个字符,因为通道 dbhandle 未打开或表 DEGREE 不存在。 我诚挚的歉意。我修好了它,它奏效了。我在 *** 上使用了更基本的变量名,却忘了更改它们。哇!谢谢你,@MKa! 请注意:此答案中没有参数化,只有字符串连接,如果您允许用户输入值,请注意 sql 注入:Bobby Tables!

以上是关于使用 R RODBC 参数化 SQL 查询的主要内容,如果未能解决你的问题,请参考以下文章

在 R 中使用 RODBC 创建循环 SQL QUERY

RODBCext:使用 sqlExecute() 时出现 SQL 42000 402 错误

参数化sql查询语句

sql参数化查询

mybatis的sql参数化查询

Sql Server参数化查询之where in和like实现详解