使用 R RODBC 参数化 SQL 查询

Parameterize SQL Queries using R RODBC

我有一个很简单的问题。

每天,我都会使用 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 中弹出一个 window 询问您 FY 的例子吗?你投入 2015 年,你将获得该财政年度的所有递减。

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

有些人可能想知道 "why can't you just change the 5 to a 6?" 这是一个公平的观点,但我担心,对于更复杂的查询,用户可能会错过 SQL 查询中将 5 更改为 6 和这会使分析混乱或减慢速度。

谢谢! 沃克

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

# 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 变量或您在代码开头为 quick/easy 更新声明的任何其他变量。

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

因此,您需要使用 GWidgets or Shiny, then pass user's input value into query. And do so with actual parameterization using RODBCext(RODBC 的扩展名)等库在 R 中创建一个类似的 GUI 弹出框,以防恶意用户运行 SQL 注入并可能擦除数据或破坏您的 SQL 服务器数据库。

下面是使用 GWidgets2Fiscal Years 组合框的示例(下面的屏幕截图)。

图书馆

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

options(guiToolkit="tcltk")

GUI 功能 (预先创建 R 和 SQL服务器 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)
}

运行 GUI

m <- mainWindow()

截图