我想使用 R 对本地存储在 SQLite 数据库中的表执行多个后续联接。我使用这种方法来保持内存不受数据(存储为 tibble)的影响,因为某些表大于大小限制R 允许单个向量。 虽然我设法执行连接并根据每个连接创建一个新表,但我宁愿更新现有表。
library(DBI)
library(dbplyr)
library(tidyverse)
con <- DBI::dbConnect(RSQLite::SQLite(),
dbname = "test")
dbplyr::copy_nycflights13(con)
dbListTables(con)
加入本地 tibbles 是可行的,但对于我的用例来说,没有足够的内存来在环境中执行此步骤。
# data stored locally
left_join(nycflights13::flights,
nycflights13::planes,
by = c("tailnum", "year")) |>
left_join(nycflights13::airlines, by = "carrier")
数据存储在 RSQLite 数据库中。第一个连接工作并返回 df1,它作为新表写入数据库。例如:
# in dplyr /dbplyr
left_join(x = tbl(con, "flights"),
y = tbl(con, "planes"),
by = c("tailnum", "year")) |>
show_query() |>
compute(name = "df1", temporary = F)
无法保存第二个查询,表 df1 已存在。例如:
left_join(x = tbl(con, "df1"),
y = tbl(con, "airlines"),
by = "carrier") |>
show_query() |>
compute(name = "df1", temporary = F)
有没有办法强制
compute()
覆盖现有表?或者有人可以建议如何在 SQL 查询中编写它?我尝试了以下方法:
query <- "
UPDATE df1
SET
name = result.name
FROM (
SELECT
carrier,
name
FROM
df1
LEFT JOIN
airlines
USING
(carrier)
) AS result
WHERE
df1.carrier = result.carrier
"
# Execute the update query
dbExecute(con, query)
但是我收到错误:
Error: no such table: df1
; dbListTables(con)
表示 df1 在数据库中。
出了什么问题?
您遇到的一个问题是数据库中的
name
中没有定义 df1
;一旦完成,您可以使用“加入更新”。
# setup
library(DBI); library(dplyr)
con <- DBI::dbConnect(RSQLite::SQLite(), dbname = "test")
dbplyr::copy_nycflights13(con)
# for the demo, we'll wipe out `df1` and regenerate it with an empty `name` column
dbExecute(con, "drop table df1")
left_join(x = tbl(con, "flights"),
y = tbl(con, "planes"),
by = c("tailnum", "year")) |>
mutate(name = NA_character_) |>
show_query() |>
compute(name = "df1", temporary = FALSE)
从这里开始,如果我们尝试使用您现有的
query
进行更新,则会收到错误:
Error: ambiguous column name: name
此外,一旦我们解决了这个问题,我们就会得到一个“非常慢”的更新(我从来没有足够的耐心让它持续超过几分钟)。从https://stackoverflow.com/a/21074659/3358272,获取提示
query <- "
UPDATE df1
SET name = (SELECT name
FROM airlines
WHERE airlines.carrier = df1.carrier)
where EXISTS (SELECT name
FROM airlines
WHERE airlines.carrier = df1.carrier)"
dbExecute(con, query)
# [1] 336776
dbGetQuery(con, "select * from df1 limit 10") |> str()
# 'data.frame': 10 obs. of 27 variables:
# $ year : int 2013 2013 2013 2013 2013 2013 2013 2013 2013 2013
# $ month : int 1 1 1 1 1 1 1 1 1 1
# $ day : int 1 1 1 1 1 1 1 1 1 1
# $ dep_time : int 517 533 542 544 554 554 555 557 557 558
# $ sched_dep_time: int 515 529 540 545 600 558 600 600 600 600
# $ dep_delay : num 2 4 2 -1 -6 -4 -5 -3 -3 -2
# $ arr_time : int 830 850 923 1004 812 740 913 709 838 753
# $ sched_arr_time: int 819 830 850 1022 837 728 854 723 846 745
# $ arr_delay : num 11 20 33 -18 -25 12 19 -14 -8 8
# $ carrier : chr "UA" "UA" "AA" "B6" ...
# $ flight : int 1545 1714 1141 725 461 1696 507 5708 79 301
# $ tailnum : chr "N14228" "N24211" "N619AA" "N804JB" ...
# $ origin : chr "EWR" "LGA" "JFK" "JFK" ...
# $ dest : chr "IAH" "IAH" "MIA" "BQN" ...
# $ air_time : num 227 227 160 183 116 150 158 53 140 138
# $ distance : num 1400 1416 1089 1576 762 ...
# $ hour : num 5 5 5 5 6 5 6 6 6 6
# $ minute : num 15 29 40 45 0 58 0 0 0 0
# $ time_hour : num 1.36e+09 1.36e+09 1.36e+09 1.36e+09 1.36e+09 ...
# $ type : chr NA NA NA NA ...
# $ manufacturer : chr NA NA NA NA ...
# $ model : chr NA NA NA NA ...
# $ engines : int NA NA NA NA NA NA NA NA NA NA
# $ seats : int NA NA NA NA NA NA NA NA NA NA
# $ speed : int NA NA NA NA NA NA NA NA NA NA
# $ engine : chr NA NA NA NA ...
# $ name : chr "United Air Lines Inc." "United Air Lines Inc." "American Airlines Inc." "JetBlue Airways" ...
df1
数据库的非规范化;如果这是您明确的意图,那么它就是按照您的意思做的,尽管在许多数据库讨论中可能建议/首选保持其规范化,其中(对于例如)字符串
"United Air Lines Inc."
存储在一个由运营商和名称组成的 16 行表中,当您进行查询时,您可以将其连接到数据中。这主要是一个理论讨论,尽管以这种方式存储 df1.name
确实需要花费数据库中还有更多空间。)