【问题标题】:Adding column to sqlite database将列添加到 sqlite 数据库
【发布时间】:2017-05-14 19:24:17
【问题描述】:

我正在尝试将在 R 中生成的向量作为新列添加到 sqlite 表中。为此,我想使用dplyr(根据这篇文章here,我安装了最新的开发版本以及dbplyr 包)。我尝试了什么:

library(dplyr)
library(DBI) 

#creating initial database and table
dbcon      <- dbConnect(RSQLite::SQLite(), "cars.db") 
dbWriteTable(dbcon, name = "cars", value = cars)
cars_tbl <- dplyr::tbl(dbcon, "cars")

#new values which I want to add as a new column 
new_values <- sample(c("A","B","C"), nrow(cars), replace = TRUE) 

#attempt to add new values as column to the table in the database
cars_tbl %>% mutate(new_col = new_values) #not working

实现此目的的简单方法是什么(不一定使用 dplyr)?

【问题讨论】:

  • dplyr 旨在避免修改输入数据。但是您可以基于现有表/数据框和mutate() 转换创建一个新表。

标签: r dplyr r-dbi rsqlite dbplyr


【解决方案1】:

不知道使用dyplr 执行此操作的方法,但您可以直接使用RSQLite 执行此操作。问题实际上不在于RSQLite,而是我不知道如何将列表传递给mutate。请注意,在您的代码中,这样的事情会起作用:

cars_tbl %>% mutate(new_col = another_column / 3.14)

无论如何,我的选择。我创建了一个玩具 cars 数据框。

cars <- data.frame(year=c(1999, 2007, 2009, 2017), model=c("Ford", "Toyota", "Toyota", "BMW"))

我打开连接并实际创建表,

dbcon <- dbConnect(RSQLite::SQLite(), "cars.db")
dbWriteTable(dbcon, name = "cars", value = cars)

添加新列并检查,

dbGetQuery(dbcon, "ALTER TABLE cars ADD COLUMN new_col TEXT")
dbGetQuery(dbcon, "SELECT * FROM cars")
  year  model new_col
1 1999   Ford    <NA>
2 2007 Toyota    <NA>
3 2009 Toyota    <NA>
4 2017    BMW    <NA>

然后您可以更新新列,但唯一棘手的是您必须提供where 声明,在这种情况下我使用年份。

new_values <- sample(c("A","B","C"), nrow(cars), replace = TRUE) 
new_values
[1] "C" "B" "B" "B"

dbGetPreparedQuery(dbcon, "UPDATE cars SET new_col = ? where year=?",
                   bind.data=data.frame(new_col=new_values,
                                        year=cars$year))

dbGetQuery(dbcon, "SELECT * FROM cars")
  year  model new_col
1 1999   Ford       C
2 2007 Toyota       B
3 2009 Toyota       B
4 2017    BMW       B

作为唯一索引,您始终可以使用 rownames(cars),但您必须将其作为列添加到数据框中,然后添加到表中。

根据@krlmlr 的建议进行编辑:确实使用dbExecute 比弃用的dbGetPreparedQuery 好得多,

dbExecute(dbcon, "UPDATE cars SET new_col = :new_col where year = :year",
          params=data.frame(new_col=new_values,
                            year=cars$year))

cmets 后编辑:前几天我还没有想到这个,但是即使是SQLite,你也可以使用rowid。我已经对此进行了测试,并且可以正常工作。

dbExecute(dbcon, "UPDATE cars SET new_col = :new_col where rowid = :id",
          params=data.frame(new_col=new_values,
                            id=rownames(cars)))

尽管您必须确保表中的 rowid 与您的 rownames 相同。无论如何,您总是可以像这样获得您的 rowid:

dbGetQuery(dbcon, "SELECT rowid, * FROM cars")
  rowid year  model new_col
1     1 1999   Ford       C
2     2 2007 Toyota       B
3     3 2009 Toyota       B
4     4 2017    BMW       B

【讨论】:

  • dbGetPreparedQuery() 已弃用,您应该可以改用dbExecute(..., params = data.frame())
  • 感谢您的回答。我对你的解决方案有一个问题。数据库表中唯一具有唯一值的字段是几乎对应于rownames(df) 的id。不同之处在于不同的数据类型。在数据库中,类型为ident,在 R 中为character。我也用numeric 尝试过,但两者都不起作用。我该如何解决?
  • 嗨@Alex 我已经修改了我的答案,如果您仍然发现问题,请告诉我。
  • 谢谢!我发现它以前已经起作用了。我在 >50000 行的钻石数据集(可通过 ggplot2 获得)上进行了尝试。它持续了几分钟,因此我一直认为 R 坏了。需要这么长时间正常吗?
  • 嗨。评估性能总是很困难,这取决于很多,例如在你的机器上。无论如何,如果您要更新 50K 寄存器,那就太多了。例如this question 有一些关于如何提高性能的提示,它不适用于 R,但其中一些提示可能适用。我会试着在周末看看,让你知道。谢谢。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-01-07
  • 2020-03-25
  • 1970-01-01
  • 2017-03-07
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多