R中的错误rsqlite_fetch

时间:2017-12-08 20:58:34

标签: r rsqlite

我有一个" CSV"具有28个变量和7400个观测值的格式数据集。我导入R中的数据集,名称为" films"而我想要清理它。通过这种方式,我使用" sqldf"和#34; SQLite"库。但是当我使用" sqldf"我收到警告,因此我的数据集也没有更新:

enter image description here

color   director_name   num_critic_for_reviews  duration
Color   James Cameron   723                       178
Color   Gore Verbinski  302                       169
Color   Sam Mendes      602                       148

我使用的代码如下:

library(RSQLite) 
library(sqldf)
db <- dbConnect(SQLite(), "tempdb")  

dbWriteTable(db,"films",films, overwrite=TRUE)

d <- sqldf(c('update films set movie_title=lower(movie_title)', 'select * from films'))
d <- sqldf(c('update films set actor_3_name=lower(actor_3_name)', 'select * from films'))
d <- sqldf(c('update films set actor_2_name=lower(actor_2_name)', 'select * from films'))
d <- sqldf(c('update films set actor_1_name=lower(actor_1_name)', 'select * from films'))
d <- sqldf(c('update films set director_name=lower(director_name)', 'select * from films'))


# Warning message:
# In rsqlite_fetch(res@ptr, n = n) :
#   Don't need to call dbFetch() for statements, only for queries

有什么问题?

1 个答案:

答案 0 :(得分:2)

这里有几个问题。

<强>第一

# 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环境中不会产生side-effects。这意味着如果您想以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等的误解。

  1. 您正在为直接SQL查询创建db句柄(不是sqldf),但您从不使用它。正如您稍后将看到的,(a)使用dbExecute(和相关函数)与db句柄,或(b)使用sqldf,不需要dbConnect和朋友们。

  2. 使用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)
    
  3. 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'))
    
  4. 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'))
    
  5. 你真的需要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)
    })