使用RSQLite将列附加到R中的SQLite表

时间:2011-07-07 21:25:51

标签: sqlite r

我有两个大数据框,我想与merge()进行外连接,但是连接表对于RAM来说太大了。我的工作是使用RSQLite包到外连接并将连接表存储回数据库。

我想在这个连接表的列上使用R函数,但我无法弄清楚如何将列追加到连接表中。我知道如何使用dbWriteTable()(如下所示),但这不是一个选项,因为连接表大于RAM。

library(RSQLite)
left <- data.frame(let = letters[rep(1:4, each = 5)], num = 1:20)
right <- data.frame(let = letters[rep(1:4, each = 5)], num = 21:40)
con <- dbConnect(dbDriver("SQLite"), dbname = tempfile())
dbWriteTable(con, "left_table", left, row.names = F)
dbWriteTable(con, "right_table", right, row.names = F)
dbGetQuery(con, "CREATE TABLE merged_table (letters TEXT, left_num INTEGER, right_num INTEGER)")
dbGetQuery(con, "INSERT INTO merged_table SELECT * FROM left_table LEFT OUTER JOIN right_table USING (let)")
fun <- function(x) rowSums(x)
temp <- dbReadTable(con, "merged_table")
dbWriteTable(con, "merged_table_new", cbind(temp, fun(temp[, 2:3])))
dbDisconnect(con)

我听说数据库在行上工作,所以我怀疑正确的解决方案可能只是在行中循环,在每行附加一个条目,但我不确定如何实现。谢谢!

(这里没有关于SQLite的任何神圣之处,我只是认为这对 ad hoc 分析会更好。)


编辑:我在bind.data中了解了dbGetPreparedQuery()选项并意识到我需要对数据库进行读取和写入连接,但我仍然遇到一些问题(即数据没有问题) t INSERT到数据库)。该脚本运行时没有错误,但也没有所需的结果。

library(RSQLite)
left <- data.frame(let = letters[rep(1:4, each = 5)], num = 1:20)
right <- data.frame(let = letters[rep(1:4, each = 5)], num = 21:40)
my.tempfile <- tempfile()
con.write <- dbConnect(dbDriver("SQLite"), dbname = my.tempfile)
con.read <- dbConnect(dbDriver("SQLite"), dbname = my.tempfile)
dbWriteTable(con.write, "left_table", left, row.names = F)
dbWriteTable(con.write, "right_table", right, row.names = F)
dbGetQuery(con.write, "CREATE TABLE merged_table (letters TEXT, left_num INTEGER, right_num INTEGER)")
dbGetQuery(con.write, "INSERT INTO merged_table SELECT * FROM left_table LEFT OUTER JOIN right_table USING (let)")
dbGetQuery(con.write, "ALTER TABLE merged_table ADD COLUMN sum INTEGER")
dbGetQuery(con.write, "ALTER TABLE merged_table ADD COLUMN mean INTEGER")

res <- dbSendQuery(con.read, "SELECT left_num, right_num FROM merged_table")
while (!dbHasCompleted(res)) {
    data.1 <- fetch(res)
    data.2 <- data.frame(rowSums(data.1), rowMeans(data.1))
    dbGetPreparedQuery(con.write, "INSERT INTO merged_table (sum, mean) VALUES (?, ?)", bind.data = data.2)
}
dbClearResult(res)

dbGetQuery(con.read, "SELECT * FROM merged_table LIMIT 5")

给出

  letters left_num right_num sum mean
1       a        1        21  NA   NA
2       a        1        22  NA   NA
3       a        1        23  NA   NA
4       a        1        24  NA   NA
5       a        1        25  NA   NA

但我期待

  left_num right_num sum mean
1        1        21  22 11.0
2        1        22  23 11.5
3        1        23  24 12.0
4        1        24  25 12.5
5        1        25  26 13.0

1 个答案:

答案 0 :(得分:2)

SQLite专家可能能够改进此解决方案,但您可以通过在创建merged_table之后立即执行此操作来完成此操作:

dbGetQuery(con, "INSERT INTO merged_table SELECT
                  letters,left_num,right_num,left_num+right_num row_sum FROM 
                    (SELECT let letters,left_table.num left_num, right_table.num right_num FROM 
                        left_table LEFT OUTER JOIN right_table USING (let))")

我认为那是一种丑陋的SQL,但似乎有效。如果要添加两列以上,则可以使用R中的paste构建查询的列添加部分(如果需要)。

要调查的其他事项可能是使用ALTER TABLE添加其他列,然后批量进行批量更新。我玩了一两分钟,但无法使它工作,但这并不意味着它不可能。

修改

以下代码创建您想要的输出。我现在有点匆忙(在出门的路上)所以while循环抛出一个错误,因为循环在达到退出条件之前到达数据的末尾,所以最后一个通过你的时间有一个空的data.1数据框,导致bind.data出错。但是如果你运行最后一个查询,你会看到所有数据都已插入。

library(RSQLite)
left <- data.frame(let = letters[rep(1:4, each = 5)], num = 1:20)
right <- data.frame(let = letters[rep(1:4, each = 5)], num = 21:40)
conn <- dbConnect(dbDriver("SQLite"), dbname = "sotemp.db")
conn.copy <- dbConnect(dbDriver("SQLite"), dbname = "sotempCopy.db")
dbWriteTable(conn, "left_table", left, row.names = F)
dbWriteTable(conn, "right_table", right, row.names = F)
dbGetQuery(conn, "CREATE TABLE merged_table1 (letters TEXT, left_num INTEGER, right_num INTEGER)")
dbGetQuery(conn.copy, "CREATE TABLE merged_table2 (letters TEXT, left_num INTEGER, right_num INTEGER, rowSum INTEGER,
                            rowMean REAL)")

dbGetQuery(conn, "INSERT INTO merged_table1 SELECT * FROM left_table LEFT OUTER JOIN right_table USING (let)")

res <- dbSendQuery(conn, "SELECT letters, left_num, right_num FROM merged_table1")
while (!dbHasCompleted(res)) {
    data.1 <- fetch(res,n=5)
    data.1 <- cbind(data.1,rowSums(data.1[,2:3]),rowMeans(data.1[,2:3]))
    colnames(data.1)[4:5] <- c("rowSum","rowMean")
    dbGetPreparedQuery(conn.copy, "INSERT INTO merged_table2 (letters, left_num, right_num,rowSum, rowMean) VALUES 
                        (?, ?, ?, ?, ?)", bind.data = data.1)
}
dbClearResult(res)

dbGetQuery(conn.copy, "SELECT * FROM merged_table2")

这绝不是完美的。我希望其他人能够摆脱并编辑/添加到此。关于你的解决方案无法正常工作的一些注意事项。

首先,INSERT向表中添加新行。你似乎期望它改变一个列中的值,这通常是UPDATE所做的工作,这可能会很麻烦。

其次,我不确定单独的读/写连接会为您带来什么。 SQLite不支持完整的读/写并发,即使使用单独的连接也是如此。因此,在您清除SELECT的结果之前,您将在尝试编写时遇到锁定错误。

第三,我在这里用于批量处理的策略是创建两个单独的数据库,在第一个数据库中循环SELECT的结果,在R中创建新列,然后在INSERT创建结果数据进入第二个数据库。