Параметризация SQL-запросов с использованием R RODBC - PullRequest
0 голосов
/ 08 июня 2018

У меня довольно простой вопрос.

Ежедневно я выполняю анализ данных в R с использованием пакета RODBC.Я подключаю его к нашему хранилищу данных с помощью 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?Вопросы запроса параметров, которые я вижу в Переполнении стека, касаются изменения данных в базе данных SQL, и меня это не интересует.Я просто хочу установить довольно простые ограничения, чтобы я мог перезапустить код.

Некоторые могут задаться вопросом "почему вы не можете просто изменить 5 на 6?"Это справедливо, но я обеспокоен тем, что при более сложных запросах пользователи могут пропустить часть в запросе SQL, чтобы изменить 5 на 6, и это может испортить анализ или замедлить его.

Спасибо!Walker

Ответы [ 2 ]

0 голосов
/ 08 июня 2018

Всплывающее окно Входной параметр является строго графическим интерфейсом MSAccess.exe.При запуске MS Access в качестве серверной базы данных (вне программного обеспечения MS Office) через ODBC запрос с неизвестным параметром завершится неудачно и возникнет ошибка сценария, вызывающего вызов ODBC.

Следовательно, вам нужно будет создать аналогичное всплывающее окно с графическим интерфейсом в R для этого, используя библиотеки, такие как GWidgets или Shiny , а затем передать значение ввода пользователяв запрос.И сделайте это с фактической параметризацией с использованием RODBCext (расширение RODBC) в случае, если злонамеренный пользователь запускает инъекцию SQL и потенциально стирает данные или уничтожает базу данных SQL Server.

Ниже приведен пример использования GWidgets2 с полем со списком для финансовых лет (снимок экрана ниже).

Библиотеки

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

options(guiToolkit="tcltk")

GUIФункция (заранее создать gif-образ R и SQLServer)

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()

Снимок экрана

GUI Output

0 голосов
/ 08 июня 2018

Вы можете создать входную переменную в начале и передать ее вашему запросу.Например:

# 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 или любую другую переменную, которую вы объявили в начале кода, для быстрого / простого обновления.

...