这里有几个问题。
首先:
# Warning message:
# In rsqlite_fetch(res@ptr, n = n) :
# Don't need to call dbFetch() for statements, only for queries
这是一个警告,而不是错误。事实上,它似乎是一个新问题RSQLite
,并且在一个开放问题中被引用:https ://github.com/r-dbi/RSQLite/issues/227 。
(为了简洁起见,我将在此答案的其余部分中将其从输出中删除,尽管每个非select
查询都会发生这种情况。)
二、RSQLite
处理数据库,期。它对 R 环境中的变量没有意见或意识,因此没有建议 R 中的变量是数据库表的直接和永久表示。(粗略地说,有类似的方法可以dbplyr
做到这一点。)
为了在 R 和某种形式的 SQL 查询之间提供这种类型的联系,sqldf
您可以像查询实际的 SQL 表一样查询 R 变量。当您执行这样的查询时,它会抓取当前看起来的 data.frame,将其插入到临时数据库表中(无论是RSQLite
另一个),运行 SQL 代码,然后返回您需要的内容。
第三:尽管有这种明显的联系,但它非常实用,因为它不会在 R 环境中产生副作用。这意味着,如果您想以 R 可以使用的方式存储结果数据,则需要将新表显式捕获到 R 变量中。
例如:
library(sqldf)
(mt <- mtcars[1:5,1:5])
# mpg cyl disp hp drat
# Mazda RX4 21.0 6 160 110 3.90
# Mazda RX4 Wag 21.0 6 160 110 3.90
# Datsun 710 22.8 4 108 93 3.85
# Hornet 4 Drive 21.4 6 258 110 3.08
# Hornet Sportabout 18.7 8 360 175 3.15
更新后,原始数据保持不变。
sqldf('update mt set cyl=5 where cyl>5')
mt
# mpg cyl disp hp drat
# Mazda RX4 21.0 6 160 110 3.90
# Mazda RX4 Wag 21.0 6 160 110 3.90
# Datsun 710 22.8 4 108 93 3.85
# Hornet 4 Drive 21.4 6 258 110 3.08
# Hornet Sportabout 18.7 8 360 175 3.15
select * from ...
您可以通过在调用中包含 a 来单独或在同一行中获取数据sqldf
:
mt2 <- sqldf(c('update mt set cyl=5 where cyl>5', 'select * from mt'))
mt2
# mpg cyl disp hp drat
# 1 21.0 5 160 110 3.90
# 2 21.0 5 160 110 3.90
# 3 22.8 4 108 93 3.85
# 4 21.4 5 258 110 3.08
# 5 18.7 5 360 175 3.15
(在这种情况下,我将它保存到mt2
,但您可以轻松地覆盖它。)
sqldf
所有这些都在FAQ 8中以各种形式进行了讨论,“8. 为什么我在更新时遇到问题?”
编辑
似乎有一些关于sqldf
等的误解。
db
您正在为直接 SQL 查询(不是)创建句柄sqldf
,但您从不使用它。正如您稍后将看到的,要么 (a) use dbExecute
(和相关函数)与db
句柄,要么 (b) use sqldf
,不需要dbConnect
和朋友。
使用时sqldf
,在每次调用sqldf
它时都会将变量的当前实例完整复制到数据库中。(这既有用又有时效率低下。对于较小的数据集,可能感觉不到时间损失,但仍然......)所以当你继续引用table films
时,它会忽略d
你创建的,因为它没有在它的调用之外推断你试图做什么的方法......它只是复制、查询和丢弃。
# assuming this is something like what you do ... but it doesn't matter
films <- read.csv("films.csv", ...)
# `-<---<---<---<---<---<---<---<---<---<---<---<---<---<---<-+-<--.
db <- dbConnect(SQLite(), "tempdb") # not used in sqldf ^ \
dbWriteTable(db, "films", films, overwrite=TRUE) # never used ^ \
# `--- is referring to --->--->--->--' \
d <- sqldf(c('update films set movie_title=lower(movie_title)', # \
'select * from films')) # \
# \ `--- (internal to sqldf) ^
# `--- refers to the original 'films' --->--->--->--'
选项 1,使用RSQLite
功能,而不是sqldf
:
db <- dbConnect(SQLite(), "tempdb")
dbWriteTable(db,"films",films, overwrite=TRUE)
dbExecute(db, 'update films set actor_3_name=lower(actor_3_name)')
# `--- repeat for all updates
films <- dbGetQuery(db, 'select * from films')
选项 2,(不是我的首选)使用在上一行创建的变量:
films <- read.csv("films.csv", ...)
# `--<---<---<---<---<---<---<---<---<---<---<---<---<---<---<---<---<-.
d <- sqldf(c('update films set movie_title=lower(movie_title)', # \
'select * from films')) # \
#\ \ `--- (internal to sqldf) ^
# \ `--- refers to original 'films' --->--->--->--->--'
# `--<---<---<---<---<---<---<---<---<---<---<---<---<---<---<---<--.
d <- sqldf(c('update d set actor_3_name=lower(actor_3_name)', # \
'select * from d')) # \
# \ `--- (internal to sqldf) ^
# `--- refers to previously-created 'd' --->--->--->'
# (repeat for other updates)
选项 3,始终引用/覆盖原始films
变量:
films <- read.csv("films.csv", ...)
# `--<---<---<---<---<---<---<---<---<---<---<---+--<---<---<---<---<---.
films <- sqldf(c('update films set movie_title=lower(movie_title)', # \
'select * from films')) # \
# \ \ `--- (internal to sqldf) ^
# \ ` --- refers to the first 'films' -->--->--->--'
# `-<---<---<---<---<---<---<---<---<---<---<---+--<---<---<---<---<--.
films <- sqldf(c('update films set actor_3_name=lower(actor_3_name)', # \
'select * from films')) # \
# \ `--- (internal to sqldf) ^
# ` --- refers to the second 'films' -->--->--->-'
# (repeat for other updates)
sqldf
效率低下。每次调用 时sqldf
,它都会将整个数据集复制到一个临时表中。每一个。时间。您可以通过将所有查询字符串组合到一个调用中来减少一些开销,如下所示:
films <- read.csv("films.csv", ...)
films <- sqldf(c('update films set actor_3_name=lower(actor_3_name)',
'update films set actor_2_name=lower(actor_2_name)',
'update films set actor_1_name=lower(actor_1_name)',
'update films set director_name=lower(director_name)',
'select * from films'))
SQL 效率低下。您的原始代码可能会针对该问题进行简化(这很好),但如果不是,那么就到这里。由于您似乎根本没有调整您的更新,因此您可以将数据清理合并到一个更新中。(这也可以使用dbExecute
。)
films <- read.csv("films.csv", ...)
films <- sqldf(c('update films set actor_3_name=lower(actor_3_name),
actor_3_name=lower(actor_3_name),
actor_2_name=lower(actor_2_name),
actor_1_name=lower(actor_1_name),
director_name=lower(director_name)',
'select * from films'))
你真的需要 SQL 吗?这可以在 R 中非常容易/快速地完成:
films <- read.csv("films.csv", ...)
films <- within(films, {
actor_3_name <- tolower(actor_3_name)
actor_2_name <- tolower(actor_2_name)
actor_1_name <- tolower(actor_1_name)
director_name <- tolower(director_name)
})