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

Posted

技术标签:

【中文标题】在 R 中使用 RODBC 创建循环 SQL QUERY【英文标题】:creating a looped SQL QUERY using RODBC in R 【发布时间】:2019-01-03 16:15:28 【问题描述】:

首先 - 感谢您抽出宝贵时间查看我的问题,无论您是否回答!

我正在尝试创建一个函数,该函数循环遍历我的 df 并使用 R 中的 RODBC 包从 SQL 中查询必要的数据。但是,我在设置查询时遇到了麻烦,因为查询的参数在每个迭代(下例)

所以我的 df 看起来像这样:

     ID     Start_Date    End_Date    
     1       2/2/2008      2/9/2008
     2       1/1/2006      1/1/2007
     1       5/7/2010      5/15/2010
     5       9/9/2009      10/1/2009

如何在我的 sql 程序中指定开始日期和结束日期?

这是我目前所拥有的:

 data_pull <- function(df) 
    a <- data.frame()
    b <- data.frame()

    for (i in df$id)
 
    dbconnection <- odbcDriverConnect(".....")

    query <- paste("Select ID, Date, Account_Balance from Table where ID = (",i,") and Date > (",df$Start_Date,") and Date <= (",df$End_Date,")")

    a <- sqlQuery(dbconnection, paste(query))
    b <- rbind(b,a)
 
  return(b)
 

但是,这不会查询任何内容。我相信这与我如何指定迭代的开始和结束日期有关。

如果有人能提供帮助,将不胜感激。如果您需要进一步的解释,请不要犹豫!

【问题讨论】:

永远不要在 SQL 查询中使用paste 连接,最好的情况是冒着语法错误的风险,最坏的情况是SQL injection(无论是否有意)。相反,使用RODBCext(相关问题:***.com/q/16178640/3358272)(除非RODBC 已经开始直接这样做,我真的很惊讶他们还没有实现它,因为它对于良好的数据库实践相当基础)。 cran.r-project.org/web/packages/RODBCext/vignettes/… 谢谢@r2evans,我会学习并尝试实现它。 第二,不要像那样使用重复的rbind,从长远来看它会破坏性能(每次调用rbind都会对所有数据进行完整副本前面和被添加)。由于RODBCext::sqlExecute 直接支持使用帧进行矢量化(参见cran.r-project.org/web/packages/RODBCext/vignettes/…,第 2.3.2 节),因此根本不需要循环。 是的,rbind 在循环内运行会导致二次复制。始终避免在循环中增长对象 谢谢你们@Parfait 我会尝试重新写这个 【参考方案1】:

当前设置会出现一些语法问题:

    循环:您不会遍历数据帧的所有行,而只会遍历单个列 df$ID 中的原子 ID 值。在同一个循环中,您将df$Start_Datedf$End_Date整个 向量传递到查询连接中。

    日期:您的日期格式与“YYYY-MM-DD”的大多数数据库日期格式不一致。还有一些其他的,比如 Oracle,你需要字符串到数据的转换:TO_DATE(mydate, 'YYYY-MM-DD')

前面提到的几个性能/最佳实践问题:

    参数化:虽然出于安全原因不需要参数化,因为您的值不是由可能注入恶意 SQL 代码的用户输入生成的,但为了可维护性和可读性,建议使用参数化查询。因此,请考虑这样做。

    不断增长的对象:根据 Patrick Burn 的 InfernoCircle 2:不断增长的对象,R 程序员应避免在循环中增长多维对象(如数据帧),这可能导致过度复制记忆。相反,在循环外once构建一个数据帧列表到rbind


话虽如此,您可以通过将数据框保存为数据库表,然后连接到最终表以进行过滤、连接查询导入,从而避免任何循环或列表需求。这假设您的数据库用户具有CREATE TABLEDROP TABLE 权限。

# CONVERT DATE FIELDS TO DATE TYPE
df <- within(df, 
          Start_Date = as.Date(Start_Date, format="%m/%d/%Y")
          End_Date = as.Date(End_Date, format="%m/%d/%Y")
)

# SAVE DATA FRAME TO DATABASE
sqlSave(dbconnection, df, "myRData", rownames = FALSE, append = FALSE)

# IMPORT JOINED AND DATE FILTERED QUERY
q <- "SELECT ID, Date, Account_Balance 
      FROM Table t
      INNER JOIN myRData r 
        ON r.ID = t.ID 
        AND t.Date BETWEEN r.Start_Date AND r.End_Date"

final_df <- sqlQuery(dbconnection, q)

【讨论】:

非常感谢您抽出宝贵的时间来完成这项工作。我真的很感激。 没问题。新年快乐,编码愉快!

以上是关于在 R 中使用 RODBC 创建循环 SQL QUERY的主要内容,如果未能解决你的问题,请参考以下文章

使用 R RODBC 参数化 SQL 查询

使用 docker、rbase 和 RODBC 连接到 sql server 时出错

R - 使用 RODBC 更新 SQL Server 上的数据

R:使用 R 更新 SQL 表循环

使用 R 与 RODBCext 和 RODBC 执行 SQL 存储过程

以编程方式构建 SQL 查询 R/Shiny/RODBC