首先想到的方法是将日期转换为文本,因为已经有了不同形式文本操作的 dbplyr 翻译。这种方法依赖于
as.character
将日期转换为字符,以及
substr
提取年、月或日作为文本。然后可以将其转换为数字并进一步处理。
(1) 设置模拟数据库连接以测试翻译(选择您喜欢的 SQL 方言):
library(dplyr)
library(dbplyr)
df = data.frame(start_dates = c('2020-01-31', '2020-02-28', '2020-03-31'))
df = tbl_lazy(df, con = simulate_mssql())
(2) 示例 - 提取日期组件,增加年份,然后重新组合:
output = df %>%
mutate(text_date = as.character(start_dates)) %>%
mutate(text_year = substr(text_date, 1, 4),
text_month = substr(text_date, 6, 7),
text_day = substr(text_date, 9, 10)) %>%
mutate(num_year = as.numeric(text_year),
num_month = as.numeric(text_month),
num_day = as.numeric(text_day)) %>%
select(start_dates, num_year, num_month, num_day) %>%
mutate(next_year = num_year + 1) %>%
mutate(next_year_text_date = paste0(next_year, '-', num_month, '-', num_day)) %>%
mutate(next_year_date = as.Date(next_year_text_date)) %>%
select(start_dates, next_year_date)
调用show_query(output)
,然后会得到以下翻译,但格式不太好。我知道嵌套查询不被认为是良好的SQL实践,但这就是dbplyr翻译的工作方式。
SELECT `start_dates`
, TRY_CAST(`next_year_text_date` AS DATE) AS `next_year_date`
FROM (
SELECT `start_dates`
, `num_year`
, `num_month`
, `num_day`
, `next_year`
, `next_year` + '-' + `num_month` + '-' + `num_day` AS `next_year_text_date`
FROM (
SELECT `start_dates`
, `num_year`
, `num_month`
, `num_day`
, `num_year` + 1.0 AS `next_year`
FROM (
SELECT `start_dates`
, TRY_CAST(`text_year` AS FLOAT) AS `num_year`
, TRY_CAST(`text_month` AS FLOAT) AS `num_month`
, TRY_CAST(`text_day` AS FLOAT) AS `num_day`
FROM (
SELECT `start_dates`
, `text_date`
, SUBSTRING(`text_date`, 1, 4) AS `text_year`
, SUBSTRING(`text_date`, 6, 2) AS `text_month`
, SUBSTRING(`text_date`, 9, 2) AS `text_day`
FROM (
SELECT `start_dates`
, TRY_CAST(`start_dates` AS VARCHAR(MAX)) AS `text_date`
FROM `df`
) `q01`
) `q02`
) `q03`
) `q04`
) `q05`
(3)提取组件,压缩:
output = df %>%
mutate(num_year = as.numeric(substr(as.character(start_dates), 1, 4)),
num_month = as.numeric(substr(as.character(start_dates), 6, 7)),
num_day = as.numeric(substr(as.character(start_dates), 9, 10)))
使用SQL翻译,show_query(output)
更加简短:
SELECT `start_dates`
, TRY_CAST(SUBSTRING(TRY_CAST(`start_dates` AS VARCHAR(MAX)), 1, 4) AS FLOAT) AS `num_year`
, TRY_CAST(SUBSTRING(TRY_CAST(`start_dates` AS VARCHAR(MAX)), 6, 2) AS FLOAT) AS `num_month`
, TRY_CAST(SUBSTRING(TRY_CAST(`start_dates` AS VARCHAR(MAX)), 9, 2) AS FLOAT) AS `num_day`
FROM `df`
希望这个可以在dbplyr可以翻译的所有SQL版本上运行。由于我无法访问每个SQL版本进行测试,因此来自已经在特定SQL版本上测试过的人的评论将会很有帮助。
RPostgres
,您可以很容易地使用lubridate
函数,如此处所示。我认为可以通过这种方式完成您要求的所有事情。如果其他SQL实现(例如MySQL)无法正常工作,则可能需要对相关软件包(例如RMySQL
)进行调整。 - Ian Gow