Здесь есть несколько проблем на работе.
Первый:
# 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
, который позволяет вам запрашивать переменные R, как если бы они были реальными таблицами SQL. Когда вы делаете такой запрос, он захватывает 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 ...
в свой вызов 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
), но никогда его не используете. Как вы увидите позже, либо (а) используйте dbExecute
(и связанные функции) с дескриптором db
, либо (б) используйте sqldf
, нет необходимости в dbConnect
и его друзьях.
При использовании sqldf
при каждом и каждом вызове sqldf
выполняется полная копия текущего экземпляра переменной в базу данных. (Это и полезно, и иногда неэффективно. С небольшими наборами данных потерянное время, вероятно, не ощущается, но все же...) Поэтому, когда вы продолжаете ссылаться на таблицу 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)
})
person
r2evans
schedule
08.12.2017
warning
заerror
. Другая проблема:dbGetQuery
предполагает, что есть данные для возврата, но вы просто обновляете; вместо этого рассмотритеdbExecute
(илиdbSendQuery
иdbClearResult
). - person r2evans   schedule 09.12.2017films
в R? - person r2evans   schedule 09.12.2017colors
наcolor
в моем наборе данныхfilms
. - person Farzad   schedule 09.12.2017