【问题标题】:Is it possible to run SQL query directly on class tbl_sql (or tbl_dbi)?是否可以直接在类 tbl_sql(或 tbl_dbi)上运行 SQL 查询?
【发布时间】:2018-02-11 08:48:56
【问题描述】:

示例代码:

library(DBI)
library(RSQLite)

# will require more details (like user, password, host, port, etc.)
con <- dbConnect(RSQLite::SQLite(), ":memory:")
data(USArrests)
dbWriteTable(con, "USArrests", USArrests)
dbListTables(con)

d0 <- tbl(con, "USArrests")
dbGetQuery(d0, "select * from USArrests")
dbGetQuery(d0, "select * from d0")

返回:

Error in (function (classes, fdef, mtable)  : 
  unable to find an inherited method for function ‘dbGetQuery’ for signature ‘"tbl_dbi", "character"’

显然我可以在 con 上使用 dbGetQuery,但想知道是否有办法让它直接在 d0 上工作。

谢谢。

【问题讨论】:

  • 不是tbl_sqltbl_dbi,但 sqldf 包可以使用 SQL 和包括 sqlite 在内的各种后端处理数据帧。 library(sqldf); sqldf("select * from USArrests limit 3")

标签: r dplyr tibble rsqlite dbplyr


【解决方案1】:

一方面,tbl() 函数是 SELECT * FROM Table 类型的 SQL 语句,它在 DBMS 上工作,并且要从数据库服务器检索数据,它需要像 collect() 这样的拉函数。另一方面,函数dbGetQuery() 使用SQL 查询将数据检索到R 会话中。两者都需要连接到服务器和一条语句,但第一个使用 SQL 翻译创建语句,另一个是编写 SQL 查询的用户。

为了说明我将在 postgreSQL DBMS 中使用时态表 tmp

# Example on postgreSQL
library(tidyverse)
library(dbplyr)
library(RPostgreSQL)
library(DBI) # This is loaded with RPostgreSQL package

con <- dbConnect(PostgreSQL(), 
                 dbname="test",
                 host="localhost",
                 port=5432,
                 user="user",
                 password="pass")

到 PostgreSQL 服务器的虚拟数据

date <- data_frame(Col1 = c("20180212", "20180213"),
                   Col2 = c("A", "B"))
dbWriteTable(con, "tmp", date, temporary = TRUE)

带有tbl()功能

tbl(con, "tmp") %>% show_query()

#><SQL> 
#>SELECT * 
#>FROM "tmp"

tbl(con, "tmp") %>% 
  mutate(date = to_date(Col1, "YYYYMMDD")) %>%
  show_query()

#><SQL>
#>SELECT "row.names", "Col1", "Col2", TO_DATE("Col1", 'YYYYMMDD') AS "date"
#>FROM "tmp"

tbl(con, "tmp") %>% 
  mutate(date = to_date(Col1, "YYYYMMDD")) %>% #this works on DBMS
  collect() %>% #This retrive to R session
  str()

#>Classes ‘tbl_df’, ‘tbl’ and 'data.frame': 2 obs. of  3 variables:
#> $ row.names: chr  "1" "2"
#> $ Col1     : chr  "20180212" "20180213"
#> $ Col2     : chr  "A" "B"
#> $ date     : Date, format: "2018-02-12" "2018-02-13"

带有dbGetQuery()功能

dbGetQuery(con, "SELECT * FROM tmp") %>% 
  str()

#>'data.frame': 2 obs. of  3 variables:
#> $ row.names: chr  "1" "2"
#> $ Col1     : chr  "20180212" "20180213"
#> $ Col2     : chr  "A" "B"

dbGetQuery(con, "SELECT * FROM tmp") %>%
  mutate(date = as.Date(Col1, format = "%Y%m%d")) %>% #This works on R session
  str()

#>'data.frame': 2 obs. of  4 variables:
#> $ row.names: chr  "1" "2"
#> $ Col1     : chr  "20180212" "20180213"
#> $ Col2     : chr  "A" "B"
#> $ date     : Date, format: "2018-02-12" "2018-02-13"

结论

tbl() 函数是 R 编程中 dbGetQuery() 的高级功能。考虑重新设计您的代码链,了解这两种功能之间的差异以及它们的最佳用途。

【讨论】:

    【解决方案2】:

    不,您不能以这种方式将dbGetQuerydplyr 一起使用,它只能与DBIConnection 一起使用。

    另外,您的第一个查询是多余的,d0 已经代表了USArrests 数据,第二个查询是无意义的。

    dplyr 使用了一些不同的方法,它使用 dplyr 动词并创建 SQL 查询:

    d0 %>% filter(Murder > 10) %>% show_query()
    

    【讨论】:

    • 嗨@m0nhawk。我知道它不起作用,问题是我怎样才能写出像“过滤器”这样的东西。它显然运行一些 SQL,我希望能够编写一个自定义函数来执行它。
    • @TalGalili 我不明白你想要什么。你想写你自己的filter?然后你可以查看dplyr开发指南。
    【解决方案3】:

    好的,查看str 有助于揭示如何使用以下命令访问所需的元素:

      con <- d0$src$con
      db_name <- db_list_tables(con)[1]
    

    【讨论】:

    • 这看起来很有趣。你能解释一下它在做什么吗?
    • 嗨 Rasmus,它正在从 dbplyr 对象(tbl_lazy,tbl_sql)获取原始连接和使用的数据库名称。这样我们就可以直接使用 dbGetQuery 之类的东西,而无需先通过 dplyr collect 函数。我个人想要它来获取行的样本 - 但只有在对象上没有使用其他 dplyr 动词时才有意义。
    猜你喜欢
    • 2012-02-22
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2022-01-20
    • 1970-01-01
    • 1970-01-01
    • 2016-05-26
    • 2020-09-29
    相关资源
    最近更新 更多