【问题标题】:Converting Date to Year-Quarter Format When Using Dbplyr使用 Dbplyr 时将日期转换为年-季度格式
【发布时间】:2021-04-02 00:54:10
【问题描述】:

我在数据库中有一个数据框,其中包含我使用 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")) 

 

【问题讨论】:

  • 仅供参考,来自您的since-deleted question,您提到需要RPostgreSQL 才能获得dbConnect。不需要。您可以在 RPostgresDBI 包中获得该功能。

标签: r postgresql date dbplyr


【解决方案1】:

dbplyr 中为一组 lubridate 函数提供了 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), "-", quarter(start_date))) %>%
    select(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-04-03 创建

【讨论】:

  • 由于某种莫名其妙的原因,我无法写入我们的 Redshfit 服务器,因此无法将数据带到本地然后将其放回服务器。我不知道为什么我的同事可以毫无问题地写入我们的服务器...
  • 上面的代码不会写回数据库。有时在服务器上处理数据然后将数据带入 R 会更有效。由于权限的原因,您可能无法写入数据库。对于某些用例,我在这里给出的答案(对我自己的问题)可能会有所帮助:stackoverflow.com/questions/66910165/…
【解决方案2】:

你能用zooas.yearqtr吗?

zoo::as.yearqtr(Sys.Date())
#[1] "2021 Q2"

要获取特定格式的数据,您可以使用format

format(zoo::as.yearqtr(Sys.Date()), '%Y-%q')
#[1] "2021-2"

【讨论】:

  • 我无法使用 as.yearqtr 转换该日期列。我如何将它应用于我的远程表“df”中的日期?我是 R 新手。感谢您的耐心等待。
  • 当你df &lt;- df %&gt;% mutate(new_date = zoo::as.yearqtr(date))时会发生什么
【解决方案3】:

因为 dbplyr 不翻译 lubridate,所以我经常用于日期操作的方法是 SQL 的小片段。你可以看到这个here的例子。

由于您需要从现有日期中提取年份和季度,第一步是识别执行此操作的 postgresql 代码片段。请注意,不同版本的 SQL 在处理日期时使用不同的函数,因此此代码将是 postgresql 特定的。

基于this linkthis link,似乎有两种方法可以提取日期的组件:

  1. EXTRACT(YEAR FROM date_column)
  2. 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`
        , `my_dates`
        , 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”格式可能有更好的替代方案。

【讨论】:

  • 感谢您的回复。运行第一个 mutate 函数成功地从整数格式的日期中提取了季度(我假设您的意思是那个而不是月份)和年份。但是,使用 CONCAT 进行的第二次变异不起作用。我收到以下错误:“错误:无法准备查询:错误:函数 concat_ws(“未知”,整数,整数)不存在提示:没有函数与给定的名称和参数类型匹配。您可能需要添加显式类型转换。”
  • 两个选项:(1) 将CONCAT(...) 包裹在sql(.) 中,就像我们对EXTRACT 代码所做的那样。 (2) 由于CONCAT_WS 似乎需要文本而不是数字输入,您可能必须先执行mutate(the_year = as.character(the_year)) 之类的操作才能将其连接起来。
  • 你是对的,我的意思是季度,但是输入了月份。已编辑答案以更正此问题。
  • CONCAT 可以成功连接 the_year 和 the_quarter,但我似乎无法将连字符加入其中。代码如下: df %>% mutate(the_quarter = sql("EXTRACT(QUARTER FROM date)"), the_year = sql("EXTRACT(YEAR FROM date)")) %>% mutate(the_quarter = as.character(the_quarter ), the_year = as.character(the_year)) %>% mutate(xyz = sql("CONCAT(the_year, the_quarter)")) %>%
  • 这个 CONCAT_WS 连接代码不想工作...mutate(xyz = sql("CONCAT_WS('-', the_year, the_quarter)")。当我运行时,我得到一个类似的错误:Error: Failed to prepare query: ERROR: function concat_ws("unknown", character varying, character varying) does not exist HINT: No function matches the given name and argument types. You may need to add explicit type casts.
猜你喜欢
  • 2015-09-13
  • 1970-01-01
  • 2021-07-25
  • 2023-01-22
  • 1970-01-01
  • 2014-03-01
  • 1970-01-01
  • 2019-11-18
  • 2015-04-29
相关资源
最近更新 更多