我有一个非常长的sqlquery,只需更改日期就需要运行几次。我擅长SAS但对R来说很陌生,所以我很难写出类似于SAS的东西。
df <- sqlQuery(datamart, paste0("Select xxxxxxxxxxxxxxxxxx from xxxxx
where date = '28Feb2018'"), as.is=TRUE, stringsAsFactors = FALSE)
你能分享一些经验吗?
谢谢!
于6/5/2018编辑:
我根据下面的答案编辑了代码,但在正确运行代码时仍然遇到一些麻烦。 目前我的代码变为:
safeqry <- function(date_string)
{require(RODBCext)
qry_string <- paste0("DELETE FROM [T_SPP] WHERE [BkDt]<=#?","#")
parms <- data.frame(date_string, stringsAsFactors=FALSE)
sqlExecute(access, qry_string, parms, fetch=TRUE)}
safeqry('2016-04-30')
错误是:
42000 -3100 [Microsoft] [ODBC Microsoft Access驱动程序]查询表达式中的日期语法错误&#39; [BkDt]&lt; =#Pa_RaM000&#39;。 [RODBCext]错误:SQLExecute失败 另外:警告信息: 在sqlExecute(access,qry_string,parms,fetch = TRUE)中:
其他代码是
query_delete = function (table, date_col, date) {
paste0('DELETE FROM [',table,'] WHERE [',date_col,']<=#',date, '#')}
sqlQuery(access, query_delete("T_SPP", "BkDt", "2018-04-30"),as.is = TRUE, stringsAsFactors = FALSE)
错误是
[1]&#34; [RODBC]错误:无法SQLExecDirect&#39; DELETE FROM [T_SPP] WHERE [BkDt]&lt; =#2018-04-30#&#39;&#34; < / p>
答案 0 :(得分:5)
与SAS宏相当的R是一个函数。因此,您编写一个函数,将日期作为参数,然后将日期传递给查询。
最简单的方法是通过字符串操作:
safeqry <- function(date_string)
{
require(RODBCext)
qry_string <- paste0("select xxxxx from yyy where date = ?")
parms <- data.frame(date_string, stringsAsFactors=FALSE)
sqlExecute(datamart, qry_string, parms, fetch=TRUE)
}
但是,这通常是不安全的,因为人们可以将恶意字符串传递给您的函数,导致它执行Bad Things.而是考虑使用RODBCext package来运行参数化查询而不是弄乱字符串:
{{1}}
答案 1 :(得分:3)
最简单的方法如下所示:
macro1 <- function(dt) {
qry <- paste0("select xxxxxxxxxx from xxxx where date='", dt, "'")
sqlQuery(datamart, qry, as.is=TRUE, stringsAsFactors=FALSE)
}
但它有一些问题:
datamart
在父(和/或全局)环境中可用且有效;如果您使用不同的连接进行测试,我保证会以您不期望的方式咬你;和更强大的功能类似于:
macro2 <- function(dt, con) {
if (length(dt) == 0L) {
stop("'dt' is not length 1")
} else if (length(dt) > 1L) {
warning("'dt' has length > 1 and only the first element will be used")
dt <- dt[[1L]]
}
qry <- sprintf("select xxxxxxxxxx from xxxx where date='%s'", sQuote(dt))
sqlQuery(con, qry, as.is=TRUE, stringsAsFactors=FALSE)
}
虽然更好的解决方案是使用变量绑定(&#34;参数化查询&#34;),这对每种数据库类型都是唯一的。正如Hong Ooi建议的那样,RODBCext
为RODBC
连接提供了此功能,但您需要更多数据库特定的连接。
如果你想变得有点懒惰并且感觉安全,那么连接总是在全球范围内,你可能会想做类似的事情:
macro2 <- function(dt, con=datamart) ...
哪个会起作用,但我仍然反对它。经验表明,显式通常更安全,更容易排除故障。
从这里开始,可以使用循环,无论是{JasonAizkalns建议的for
循环,还是可能类似:
answers <- lapply(vector_of_dates, macro2)
答案 2 :(得分:1)
有几种方法可以做到这一点,但既然你说你是R
的新手,这可能是一种自然的方法。首先,创建一个函数,允许您更改select_cols
,tbl
和date
并返回一个字符串:
make_query <- function(select_cols, tbl, date) {
paste0("SELECT ", select_cols, " FROM ", tbl, " WHERE date = '", date, "';")
}
make_query("*", "my_table", "28Feb2018")
[1] "SELECT * FROM my_table WHERE date = '28Feb2018';"
make_query("*", "different_table", "28Feb2018")
[1] "SELECT * FROM different_table WHERE date = '28Feb2018';"
然后你可以创建一个日期向量来循环:
various_dates <- c("28Feb2018", "01Mar2018", "02Mar2018")
for (date in seq_along(various_dates)) {
make_query("*", "my_table", various_dates[date])
}
当然,您可以修改循环体以使用sqlQuery
函数:
for (date in seq_along(various_dates)) {
sqlQuery(datamart, make_query("*", "my_table", various_dates[date]),
as.is = TRUE, stringsAsFactors = FALSE)
}
由于您希望保存结果,因此您可以预先分配与日期数相同的空列表并保存这些结果:
df <- vector("list", length(various_dates))
for (date in seq_along(various_dates)) {
df[[date]] <- sqlQuery(datamart, make_query("*", "my_table", various_dates[date]),
as.is = TRUE, stringsAsFactors = FALSE)
}