【问题标题】:Using Dates with RSQLite在 RSQLite 中使用日期
【发布时间】:2012-11-07 20:44:06
【问题描述】:

如何使用 RSQLite 编写带有日期的 SQL 查询。下面是一个例子。 dbGetQuery 不返回任何行。

require(RSQLite)
require(ggplot2)
data(presidential)
m <- dbDriver("SQLite")
tmpfile <- tempfile('presidential', fileext='.db')
conn <- dbConnect(m, dbname=tmpfile)
dbWriteTable(conn, "presidential", presidential)
dbGetQuery(conn, "SELECT * FROM presidential WHERE Date(start) >= Date('1980-01-01')")

【问题讨论】:

  • 我相信 SQLite 没有任何原生日期类型。我一直将它们存储为文本。例如,所有 SQLite 日期/时间函数(如 date())都作用于字符串,而不是“日期对象”或整数。

标签: r


【解决方案1】:

只是为了说明,这很好用:

tmpfile <- tempfile('presidential', fileext='.db')
conn <- dbConnect(m, dbname=tmpfile)
p <- presidential
p$start <- as.character(p$start)
p$end <- as.character(p$end)

dbWriteTable(conn, "presidential", p)
dbGetQuery(conn, "SELECT * FROM presidential WHERE start >= '1980-01-01'")

您可以在文档here 中了解 SQLite 中缺少原生日期类型的信息。我在 SQLite 中使用字符串作为日期已经很长时间了,以至于我完全忘记了这个问题。

是的,我编写了一个小型 R 函数,可以将数据框中的任何日期列转换为字符。对于简单的比较,将它们保存在 YYYY-MM-DD 中就足够了,如果我需要进行算术运算,我会在 R 中进行转换。

【讨论】:

  • @joran - 你愿意分享转换日期列的函数吗?
  • @boshek 没什么特别的,因为在这种特殊情况下,我 100% 确定格式将始终为 YYYY-MM-DD,所以我只是遍历列,测试它是否是 Date 类然后将其强制转换为字符。
【解决方案2】:

根据@joran 的回答,这是一个简单的函数,用于将日期列转换为 data.frame 的字符串。

mutate(df, across(where(is.Date), ~ format(.x, "%Y.%m.%d")))

【讨论】:

    【解决方案3】:

    我发现使用 RSQLitedplyr 是使用 R 和 SQLite 保持类型一致的最便捷方式。特别是,extendend_types = TRUE 确保 DATEDATETIME / TIMESTAMPTIME 类型的列映射到相应的 R 类(至少在版本 2.2.8 之后为 RSQLite)。

    library(dplyr)
    library(RSQLite)
    library(ggplot2)
    
    data(presidential)
    
    mydb <- dbConnect(SQLite(), "presidential.sqlite", extended_types = TRUE)
    dbWriteTable(mydb, "presidential", presidential)
    
    tbl(mydb, "presidential") %>% 
      filter(start >= as.Date("1980-01-01")) %>% 
      collect()
    

    您还可以将后一个集合制定为 get 查询:

    dbGetQuery(mydb, "SELECT * FROM presidential WHERE start >= CAST('1980-01-01' AS DATE)")
    

    【讨论】:

      【解决方案4】:

      正如@joran 建议的那样,在 SQLlite 中以文本形式保存日期似乎是目前最好的方法。

      我使用@Richard Knight 的方法进行转换,但使用 ISO 格式,在写入数据帧之前将日期更改为字符串:

      local_df %>% mutate(across(where(lubridate::is.Date), ~ format(.x, "%Y-%m-%d")))
      

      可以使用 sql 翻译远程操作日期,特别是:

      remote_df %>% mutate(date_as_number = julianday(date_as_string))
      remote_df %>% mutate(date_as_string = date(date_as_number))
      

      注意第二个是date 而不是as.Date。这是因为as.Date 将被转换为CAST(date_as_number AS DATE) 而我们想要的是使用SQLLite 的date() 函数和julianday() 返回的浮点数。

      可以自动将远程日期字符串映射回日期,如果您:

      collect <- function(remote_df, ...) {
        raw = remote_df %>% dplyr::collect(...)
        isoDateString = function(x) return(is.character(x) & all(na.omit(stringr::str_detect(x,"[0-9]{4}-[0-9]{2}-[0-9]{2}"))) & !all(is.na(x)))
        raw = raw %>% mutate(across(where(isoDateString), ~ as.Date(.x, "%Y-%m-%d")))
        maybeJulian = function(x) {return(is.double(x) & all(na.omit(x>2440587.5)) & all(na.omit(x<2488069.5)) & !all(is.na(x)))}
        raw = raw %>% mutate(across(matches(".*(D|d)ate.*") & where(maybeJulian), ~ as.Date(.x-2440587.5, "1970-01-01")))
        return(raw)
      }
      

      maybeJulian 函数中明显的随机数对应于1970-01-012100-01-01

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2014-04-21
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多