【问题标题】:Replacing SQL database table with transformed data in dplyr用 dplyr 中的转换数据替换 SQL 数据库表
【发布时间】:2016-05-22 11:23:27
【问题描述】:

我在 dplyr 中转换数据时经常替换数据,尤其是在处理大型数据集时。当我使用 SQL 支持的数据集时,我不确定如何优雅地做到这一点,至少不是使用 SQLite。

我在 dplyr DB vignettes 或 SO 上找不到任何关于这个目标的讨论,这也让我想知道我首先做的事情是否有问题;但是,这似乎是处理大型数据集的一种自然方式。

无论如何,最直观的方法是行不通的:

library(dplyr)
library(RSQLite)

db2 <- src_sqlite("trouble.sqlite", create = TRUE)
trouble <- data.frame(values = c(5, 1, 3))
trouble.db <- copy_to(db2, trouble, temporary = FALSE)

collect(trouble.db) # 5, 3, 1

trouble.db <- trouble.db %>% arrange(values)
collect(trouble.db) # 1, 3, 5

trouble.in <- tbl(db2, sql("SELECT * from trouble"))
collect(trouble.in) # 5, 3, 1

就地复制的另一种直观语法给出“表已存在”错误:

trouble.db <- copy_to(db2, as.data.frame(trouble.db), name="trouble", temporary = FALSE)

一种解决方案是手动删除表并重建它,这是我一直在做的:

db2$con %>% db_drop_table(table = "trouble")
trouble <- collect(trouble.db)
trouble.db <- copy_to(db2, trouble, temporary = FALSE)

另一个是放弃替换并创建一系列临时表,我觉得这不美观,但我认为这可能是推荐的范例:

trouble_temp <- data.frame(values = c(5, 1, 3))
trouble_temp.db <- copy_to(db2, trouble_temp, temporary = TRUE)
trouble <- trouble.db %>% arrange(values)
trouble.db <- copy_to(db2, trouble, temporary = FALSE)

我怀疑“删除并重新复制”最终会成为答案,但出于对美丽解决方案的热爱,我想我会问是否有更好的方法。

【问题讨论】:

  • 你好大卫。您能否提供一些有关您为什么要替换数据库中的原始数据的背景信息?鉴于您已经编写过的内容,最安全的过程是操作数据 > 写入 DBMS 上的新永久表 > DROP TABLE 以删除原始表 > ALTER TABLE 以使用原始名称重命名新表。这样,在新数据成功保存到 DBMS 之前,您不会删除原始表。
  • 嗨,格雷格,老实说,差不多两年后,我不记得我在追求什么。这些天来,我只是将 Spark 用于这类事情。
  • @大卫布鲁斯:大声笑,我试图找到一些答案,然后我看到了你的评论。好吧,也许两年后我也在使用 spark,但现在我只是用 R 从 SQL 服务器读取表。
  • 我也来过这里。 @LenGreski,我要补充的一件事是,您还可以将copy_to 与临时表一起使用,并在原始表中加上UPDATE(或upsert)语句。我经常使用它,因为我正在处理具有多个依赖项的表,在这些表中更容易保留原始表(如果你已经设置好了,你可以获得很好的时间戳日志记录)。如果有帮助,很高兴发布答案。
  • 观点是你的朋友。您甚至可以使用临时视图(取决于您的 SQL 风格)。

标签: sql r sqlite dplyr


【解决方案1】:

对于多年后发现这一点的任何人。

声明

trouble.db %>% arrange(values)

创建一个发送到数据库并在您collect 结果时执行的 SQL 查询。

我们可以看到这样的SQL

trouble.db %>% arrange(values) %>% show_query()
SELECT *
FROM `trouble`
ORDER BY `values`

显然,这样的查询不能修改它正在查询的实际数据。

要修改数据,我们可以使用DBI包中的dbWriteTable函数

library(dplyr)
library(RSQLite)

# Will use this connection object for all our DB interactions
con <- DBI::dbConnect(RSQLite::SQLite(), dbname = ":memory:")

trouble <- data.frame(values = c(5, 1, 3))
trouble.db <- copy_to(con, trouble, temporary = FALSE)

collect(trouble.db) # 5, 3, 1

# This is just a query
trouble.db <- trouble.db %>% arrange(values)
collect(trouble.db) # 1, 3, 5

# The data shouldn't be modified yet
trouble.in <- tbl(con, sql("SELECT * from trouble"))
collect(trouble.in) # 5, 3, 1

# Now we are modifying the data
DBI::dbWriteTable(
  con, "trouble", collect(trouble.db),
  overwrite = TRUE
)

tbl(con, sql("SELECT * from trouble")) %>% collect() # 1, 3, 5

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-04-28
    • 1970-01-01
    • 2022-11-21
    • 1970-01-01
    • 1970-01-01
    • 2011-12-05
    相关资源
    最近更新 更多