在R中围绕多个SQL查询包装函数?

时间:2013-10-28 14:00:10

标签: r sqldf

我有一些SQL查询基本上按时间解析数据集(POSIXct日期格式):

library(sqldf)
data_2013 <- sqldf("SELECT * FROM data WHERE strftime('%Y-%m-%d', time,
'unixepoch', 'localtime') >= '2013-01-01' AND strftime('%Y-%m-%d', time,
'unixepoch', 'localtime') <= '2013-12-31'")

data_2012 <- sqldf("SELECT * FROM data WHERE strftime('%Y-%m-%d', time,
'unixepoch', 'localtime') >= '2012-01-01' AND strftime('%Y-%m-%d', time,
'unixepoch', 'localtime') <= '2012-12-31'")

data_2011 <- sqldf("SELECT * FROM data WHERE strftime('%Y-%m-%d', time,
'unixepoch', 'localtime') >= '2011-01-01' AND strftime('%Y-%m-%d', time, 
'unixepoch', 'localtime') <= '2011-12-31'")

然而,这段代码对我来说似乎很笨拙。有没有一种巧妙的方法将它包装成一个函数或其他一些使它更短的方法,同时仍然吐出相同的3个独立的数据集?

2 个答案:

答案 0 :(得分:4)

介于&fn $ 使用between并通过strptimesqldf前缀来fn表达式,以执行字符串插值:

Time <- "strftime('%Y-%m-%d', time, 'unixepoch', 'localtime')"
st <- '2013-01-01'
en <- '2013-12-31'
fn$sqldf("select * from data where $Time between '$st' AND '$en' ")

如果需要,可以很容易地将其作为剩余解决方案的功能。

年度如果是一年,可以简化为:

Year <- "strftime('%Y', time, 'unixepoch', 'localtime')"
yr <- '2013'    
sql <- "select * from data where $Year = '$yr' "  
fn$sqldf(sql)

我们可以创建一个这样的数据框列表:

Map(function(yr) fn$sqldf(sql), as.character(2011:2013))

R / sqldf 另一种可能性是首先在R中添加一个字符列:

data$Year <- format(data$time, "%Y")
yr <- '2013'    
sql <- "select * from data where Year = '$yr' "
fn$sqldf(sql)

R 请注意,在R中直接执行此操作并不困难:

yr <- "2013"
subset(data, format(time, "%Y") == yr)

还要将其拆分为数据框列表,每年一个:

split(data, format(data$time, "%Y"))

H2 sqldf也可以与某些其他数据库一起使用。 SQLite的问题在于它没有日期/时间类型,但H2数据库直接支持日期/时间作为一种类型,因此它大大简化了。如果sqldf看到RH2已加载,它将使用它而不是SQLite:

library(RH2)
library(sqldf) 
yr <- 2013
sql <- "select * from data where year(time) = $yr"
fn$sqldf(sql)

答案 1 :(得分:2)

使用paste0,您可以实现此目的:

sqlfun <- function(startdate,stopdate){
sqldf(paste0("SELECT * FROM data WHERE strftime('%Y-%m-%d', time,
    'unixepoch', 'localtime') >= '",startdate,"' AND strftime('%Y-%m-%d', time,
    'unixepoch', 'localtime') <= '",stopdate,"'"))
}

sqlfun('2013-01-01','2013-12-31')