将 RpostgreSQL 与 sqldf 一起使用会使 R 崩溃

Posted

技术标签:

【中文标题】将 RpostgreSQL 与 sqldf 一起使用会使 R 崩溃【英文标题】:Using RpostgreSQL with sqldf crashes R 【发布时间】:2021-12-30 11:17:12 【问题描述】:

我正在使用sqldf 在 SQL 中训练一些 r 用户。在加载sqldf 之前加载RPostgreSQLRH2 将更改sqldf 使用的默认SQL。这适用于 h2,但每次我加载 RPostgreSQL 时,R 都会在第一次尝试查询时崩溃。我想让sqldfRPostgreSQL 一起使用,以启用SQLiteh2 中缺少的日期功能。

# packages
library(tidyverse)
# library(RH2) # comment out this row or the next to determine default SQL for sqldf
library(RPostgreSQL) 
library(sqldf)

输出确认“sqldf 将默认使用 PostgreSQL”

创建一些数据:

set.seed(42)
N <- 1e6

sales <- tibble(
    buyer_id = 1:N/100,
    sales_date = sample(seq(as.Date('2018/01/01'), as.Date('2021/01/01'), by="day"), N, replace = TRUE),
    sales_amount = rpois(N, 200)
) 

崩溃R:

sqldf("
select 
    max(sales_date) 
from sales
")

"R 会话中止 R 遇到致命错误 会话已终止”

【问题讨论】:

加载 sqldf 和 RPostgreSQL 的顺序无关紧要。您是否还阅读了?sqldf 并为 postgresql 正确配置了它?你安装postgreSQL吗?没有R可以用吗? h2 有 18 个时间和日期函数,所以你可能不需要 postgresql。 h2database.com/html/functions.html @G.Grothendieck h2 中缺少的关键日期函数是 date_trunc()。我没有看到允许在 h2 中按周、月、qtr、yr 快速分组日期的等效函数。 h2 用户必须分两步解析出年和周或年月,然后重新组合。 我已经阅读了?sqldf,并进行了相应的配置。该错误似乎与 RPostgreSQL 有关。 (1) 如果您只需要该功能进行分组,则在 h2 中使用 formatdatetime。或者使用年、月等函数,将它们组合起来得到你需要的。 (2) 我相信 h2 实际上确实有 trunc_date 但它只在 postgresql 模式下打开,因为它不是标准 SQL。您可能需要修改 RH2 才能做到这一点。 【参考方案1】:

如果不使用 H2 的唯一原因是 date_trunc,那么这里有一些解决方法。

1) 宏 以下是截断到年/季度/月/周开始的解决方法。这些函数充当宏,可扩展为 H2 接受的代码。一定要在 sqldf 前面加上 fn$ 并用反引号括起来以打开替换。请注意,在每种情况下,参数都是一个字符串。将verbose=TRUE 参数添加到sqldf 以查看生成的代码。

library(RH2)
library(sqldf)

trunc_year <- function(x) sprintf("DATEADD(day, 1-day_of_year(%s), %s)", x, x)
trunc_qtr <- function(x) sprintf("DATEADD(month, 3*(quarter(%s)-1), %s)", x, 
  trunc_year(x))
trunc_month <- function(x) sprintf("DATEADD(day, 1-day_of_month(%s), %s)", x, x)
trunc_week <- function(x) sprintf("DATEADD(day, -iso_day_of_week(%s), %s)", x, x)

# test
DF <- data.frame(x = as.Date("2021-11-15"))
fn$sqldf("select x, 
                `trunc_year('x')` year, 
                `trunc_qtr('x')` qtr,
                `trunc_month('x')` month,
                `trunc_week('x')` week
          from DF")
##            x       year        qtr      month       week
## 1 2021-11-15 2021-01-01 2021-10-01 2021-11-01 2021-11-14

2) 修补 RH2 另一种可能性是使用具有date_trunc 的较新版本的 H2 修补您安装的 RH2。为此,我们在 RH2 中删除了包含 H2 的 h2-1.3.175.jar 文件,并将其替换为较新版本的 h2-1.4.200.jar。只要您在 RH2 安装的 java 子目录中具有写入权限,这应该可以工作。只需在 R 中运行此代码,您的 RH2 安装就会被修补。

u <- "https://h2database.com/h2-2019-10-14.zip"
z <- basename(u)
tmp <- tempdir()  # create temporary dir 
old.dir <- setwd(tmp)  # go to it
download.file(u, z)  # download u
unzip(z, "h2/bin/h2-1.4.200.jar")  # extract jar from zip file

# copy new jar file to RH2 installation and remove old one
new.jar <- file.path(tmp, "h2", "bin", "h2-1.4.200.jar")
old.jar <- dir(system.file("java", package = "RH2"), "h2.*jar$", full.names = TRUE)
if (basename(old.jar) != basename(new.jar)) 
  file.copy(new.jar, dirname(old.jar))
  file.remove(old.jar)

setwd(old.dir)  # return to original directory

# test
library(RH2)
library(sqldf)
sqldf("select h2version()")
##   '1.4.200'
## 1   1.4.200
# see more tests in (3) below

3) 重建 RH2 另一种可能性是使用具有date_trunc 的较新版本的 H2 创建新的 RH2 源版本。第一个参数是“年”、“季度”、“月”或“周”,第二个参数是日期。因此,如果您愿意用这个新的 H2 版本重建 RH2,那么它是可用的。

(a) 从https://cran.r-project.org/package=RH2下载RH2的源码并解压,创建一个目录树RH2。

(b) 下载这个 h2 zip https://h2database.com/h2-2019-10-14.zip 并从该 zip 文件中提取 h2/bin/h2-1.4.200.jar 并将 jar 文件放在 RH2 源的 RH2/inst/java 目录中删除旧的一、h2-1.3.175.jar

(c) 像这样重建和测试 RH2:

# rebuild RH2
# cd to the RH2 directory containing its DESCRIPTION file
setwd("...whatever.../RH2")

# build RH2 
#  on Windows this needs Rtools40 (not an R package)
#  https://cran.r-project.org/bin/windows/Rtools/
library(devtools)
build()
install(args = "--no-multiarch")

# test
library(RH2)
library(sqldf)
sqldf("select h2version()") # check it's the latest version
##   '1.4.200'
## 1   1.4.200

DF <- data.frame(x = as.Date("2000-11-15"))
sqldf("select date_trunc('month', x) from DF")
##   DATE_TRUNC('month', x)
## 1             2000-11-01

【讨论】:

以上是关于将 RpostgreSQL 与 sqldf 一起使用会使 R 崩溃的主要内容,如果未能解决你的问题,请参考以下文章

是否可以将 Spark 中的 data.table 与 Spark Dataframes 一起使用?

使用 RPostgreSQL 和 dplyr 将 R 连接到 Redshift 的理论是啥

如何使用 dplyr 和 RPostgreSQL 将 r 连接到 redshift?

r 使用R中的sqldf将CSV导入Sqlite

R RPostgreSQL 使用 SSL 连接到远程 Postgres 数据库

可以使用sqldf将数据库中已经存在的表的数据导入R中的data.frame吗?