R 使用 RSQLite、DBI 和 dbplyr,在 RSQLite 中不能有超过一个 table 以进行连接

R using RSQLite, DBI and dbplyr, can't have more than one table in the RSQLite in order to make a join

我很难理解这三个包的行为:RSQLiteDBIdbplyr

我正在使用 mtcars 数据框并使用 tibble 包加载它以将汽车名称添加为行之一。

library(tibble)

mtcars <- tibble::as_tibble(mtcars, rownames = 'car')  

我还创建了自己的 table,其中包含有关所有这些汽车的制造地点的信息:

car <- c("Mazda RX4", "Mazda RX4 Wag", "Datsun 710", "Hornet 4 Drive", "Hornet Sportabout", "Valiant", "Duster 360", "Merc 240D", "Merc 230", "Merc 280", "Merc 280C", "Merc 450SE", "Merc 450SL", "Merc 450SLC", "Cadillac Fleetwood", "Lincoln Continental", "Chrysler Imperial", "Fiat 128", "Honda Civic", "Toyota Corolla", "Toyota Corona", "Dodge Challenger", "AMC Javelin", "Camaro Z28", "Pontiac Firebird", "Fiat X1-9", "Porsche 914-2", "Lotus Europa", "Ford Pantera L", "Ferrari Dino", "Maserati Bora", "Volvo 142E")

origin <- c("Japan", "Japan", "Japan", "United States", "United States", "United States", "United States", "Germany", "Germany", "Germany", "Germany", "Germany", "Germany", "Germany", "United States", "United States", "United States", "Italy", "Japan", "Japan", "Japan", "United States", "United States", "United States", "United States", "Italy", "Germany", "British", "United States", "Italy", "Italy", "Sweden")

cars_origin_tbl <- tibble(car, origin)

通过创建这两个 table,我可以练习使用 R 进行连接。这是一个示例,其中包含两种不同的方式来编写 semi_join:

mtcars %>% dplyr::semi_join(cars_origin_tbl, by = 'car') -> mtcars_semi_join

# another method using value matching

mtcars_semi_join <- mtcars %>%
  filter(car %in% cars_origin_tbl$car)

但我真的很想对使用 SQL 语法进行连接的 table 感到更舒服。我即将从事一项涉及更多 SQL 的工作,我真的很想在开始之前学习一下。对我来说,最好的学习方式就是做这些事情。自己看网上的例子不适合我。

所以我在这里尝试使用这些 R 包创建一个 SQL 版本的东西。

library(dbplyr)
library(RSQLite)
library(DBI)

Andrew Couch 的这段 YouTube 视频非常有帮助。 Here is the link.

sql_mtcars <- mtcars
con <- RSQLite::dbConnect(SQLite(), ":memory:")
dplyr::copy_to(con, sql_mtcars)

sql_mtcars_db <- tbl(con, "sql_mtcars")

sql_mtcars_db %>%
  dplyr::select(car, mpg, wt) %>%
  dplyr::show_query()

这个show_query东西很有意思。它显示 dplyr 代码的 SQL 版本。

并向我展示了如何使用 dbListTables.

找到列出的 table
dbListTables(con)

dbGetQuery 将 运行 代码并获得预期的输出。

DBI::dbGetQuery(con, '
SELECT sql_mtcars.mpg, sql_mtcars.wt
FROM sql_mtcars
  ')

这是我感到困惑的地方。我正在尝试将 cars_origin_tbl 放入 RSQLite,然后练习加入两个不同的 table。

cars_origin_tbl <- cars_origin_tbl
con <- dbConnect(SQLite(), ":memory:")
copy_to(con, cars_origin_tbl)

cars_origin_tbl_db <- tbl(con, "cars_origin_tbl")

dbListTables(con)

在我 运行 dbListTables() 之后,我的第一个 sql_mtcars 就好像被遗忘了并消失了。

现在这个 dbGetQuery 工作正常,因为我只是调用较新的 table。

DBI::dbGetQuery(con, '
SELECT cars_origin_tbl.car
FROM cars_origin_tbl
  ')

但是另一个 dbGetQuery 不起作用,因为我指的是两个 table,我认为此时它们都在 RSQLite 中。我收到一条消息说没有 sql_mtcars.

DBI::dbGetQuery(con, '
SELECT sql_mtcars.mpg, sql_mtcars.wt
FROM sql_mtcars
LEFT JOIN cars_origin_tbl 
ON sql_mtcars.car = cars_origin_tbl.car;
  ')

Error: no such table: sql_mtcars

我基本上是在尝试让两个 table 进入连接,这样我就可以练习加入它们,但我不确定如何让两个 table 都进入连接而不会消失.

con <- RSQLite::dbConnect(SQLite(), ":memory:")
con2 <- RSQLite::dbConnect(SQLite(), ":memory:")
dplyr::copy_to(c(con, con2), cars_origin_tbl)

Error in UseMethod("copy_to") : 
  no applicable method for 'copy_to' applied to an object of class "list"

解决方案是对两个 table 使用相同的连接。以下作品:

# create data base connection
con <- RSQLite::dbConnect(SQLite(), ":memory:")

# copy tables to data base
dplyr::copy_to(con, sql_mtcars)
dplyr::copy_to(con, cars_origin_tbl)

# check contents of data base
dbListTables(con)

# create local pointer to remote table
sql_mtcars_db <- tbl(con, "sql_mtcars")
cars_origin_tbl_db <- tbl(con, "cars_origin_tbl")

您现在可以 semi-join 这两个 table:

mtcars_semi_join = sql_mtcars_db %>%
  semi_join(cars_origin_tbl_db, by = 'car')

show_query(mtcars_semi_join)

生成以下内容SQL:

SELECT * FROM `sql_mtcars` AS `LHS`
WHERE EXISTS (
  SELECT 1 FROM `cars_origin_tbl` AS `RHS`
  WHERE (`LHS`.`car` = `RHS`.`car`)

附带说明一下,sql_mtcarssql_mtcars_db 是不同的 R 对象。第一个是本地 R 内存中的 table。第二个是存储在数据库中的远程 table 的本地访问点。