问题描述
我在数据库中有一个数据框,其中包含我使用 RPostgres/Rpostgresql 和 dbplyr 提取的日期维度。每个日期的格式为“YYYY-MM-DD”,我需要添加一个新的日期(或字符)维度,以反映年季度格式“YYYY-Q”(带破折号,而不是期间)。
鉴于我不能将 lubridate 与 dbplyr 一起使用,我将如何实现这一点?
感谢您的帮助!这是我目前所拥有的简化版本,因此您可以看到我正在使用哪些包以及我如何连接到数据库。
# Packages
library(RPostgres)
library(RPostgresql)
library(dplyr)
library(dbplyr)
# Connect to db
drv <- dbDriver("Postgres")
# Setup connect to db
conn <- dbConnect(drv,dbname = etc,)
# Define table to use in db
table <- tbl(conn,in_schema("xyz","abc"))
#Select columns and filter
df <- table %>%
#Filter for pertinent data
filter(date > as.Date("2018-01-01") & date <= as.Date("2020-01-01"))
解决方法
你能使用zoo
的{{1}}吗?
as.yearqtr
要获取特定格式的数据,您可以使用 zoo::as.yearqtr(Sys.Date())
#[1] "2021 Q2"
:
format
,
因为 dbplyr 不翻译 lubridate,所以我经常用于日期操作的方法是 SQL 的小片段。您可以看到此 here 的示例。
由于您需要从现有日期中提取年份和季度,因此第一步是识别执行此操作的 postgresql 代码片段。请注意,不同版本的 SQL 在处理日期时使用不同的函数,因此此代码将特定于 postgresql。
基于 this link 和 this link,似乎有两种方法可以提取日期的组成部分:
EXTRACT(YEAR FROM date_column)
DATE_PART('year',date_column)
我将使用下面的第一种方法。
当我使用 SQL 片段时,我还将按照 this link 使用 SQL 进行连接。例如:CONCAT(year_column '-',quarter_column)
。所以我的输出将是一列文本类型。
将这些组合在一起给出:
library(dplyr)
library(dbplyr)
df = data.frame(my_num = c(1,2,3),my_dates = c('2000-01-01','2000-02-02','2000-03-03'))
df = tbl_lazy(df,con = simulate_postgres()) # simulated remote table
output = df %>%
mutate(the_quarter = sql("EXTRACT(QUARTER FROM my_dates)"),the_year = sql("EXTRACT(YEAR FROM my_dates)")) %>%
mutate(quarter = CONCAT(the_year,'-',the_quarter))
调用 show_query(output)
允许我们检查生成的 postgresql 查询:
SELECT `my_num`,`my_dates`,`the_quarter`,`the_year`,CONCAT(`the_year`,`the_quarter`) AS `quarter`
FROM (
SELECT `my_num`,EXTRACT(QUARTER FROM my_dates) AS `the_quarter`,EXTRACT(YEAR FROM my_dates) AS `the_year`
FROM `df`
) `q01
但没有那么好的格式。据我所知,这是一个有效的 postgresql 函数,所以我们可以期待它的工作。
根据您的应用,您可能还需要考虑 this question,尤其是 this answer。因为可能有更好的替代 'YYYY-Q' 格式。
,一堆 lubridate
函数在 dbplyr
中被赋予了 SQL 翻译。所以下面的代码对我有用。
这样做的一个优点是如果谨慎使用,您可以将数据的位置移动到最有效的位置(在服务器上或本地)。
library(dplyr,warn.conflicts = FALSE)
library(DBI)
library(lubridate)
#>
#> Attaching package: 'lubridate'
#> The following objects are masked from 'package:base':
#>
#> date,intersect,setdiff,union
pg <- dbConnect(RPostgres::Postgres(),bigint = "integer")
calls <- tbl(pg,sql("SELECT * FROM streetevents.calls"))
calls %>%
mutate(yq = paste0(year(start_date),"-",quarter(start_date))) %>%
select(start_date,yq)
#> # Source: lazy query [?? x 2]
#> # Database: postgres [iangow@/tmp:5432/crsp]
#> start_date yq
#> <dttm> <chr>
#> 1 2013-09-10 19:30:00 2013-3
#> 2 2003-10-22 15:00:00 2003-4
#> 3 2009-10-22 16:00:00 2009-4
#> 4 2017-02-09 06:00:00 2017-1
#> 5 2010-02-22 22:00:00 2010-1
#> 6 2016-08-08 20:30:00 2016-3
#> 7 2016-05-11 13:00:00 2016-2
#> 8 2012-05-15 16:20:00 2012-2
#> 9 2004-08-19 21:00:00 2004-3
#> 10 2017-07-06 13:30:00 2017-3
#> # … with more rows
calls %>%
collect(n = 10) %>%
mutate(yq = paste0(year(start_date),yq)
#> # A tibble: 10 x 2
#> start_date yq
#> <dttm> <chr>
#> 1 2013-09-10 19:30:00 2013-3
#> 2 2003-10-22 15:00:00 2003-4
#> 3 2009-10-22 16:00:00 2009-4
#> 4 2017-02-09 06:00:00 2017-1
#> 5 2010-02-22 22:00:00 2010-1
#> 6 2016-08-08 20:30:00 2016-3
#> 7 2016-05-11 13:00:00 2016-2
#> 8 2012-05-15 16:20:00 2012-2
#> 9 2004-08-19 21:00:00 2004-3
#> 10 2017-07-06 13:30:00 2017-3
由 reprex package (v1.0.0) 于 2021 年 4 月 3 日创建