2011-07-07 34 views
1

我有兩個大數據框,我想用外部連接merge(),但連接的表對RAM太大。我的解決方法是使用RSQLite包到外部聯接並將聯接的表存回數據庫。使用RSQLite將列追加到R中的SQLite表

我想在這個連接表中的列上使用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這裏,我只是認爲這將是這個特設分析更好。)


編輯:我在dbGetPreparedQuery()瞭解了bind.data選項,並意識到我需要一個讀取和寫入連接到數據庫,但我仍然有一些問題(即數據庫沒有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 

回答

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中創建新列,然後將生成的數據輸入第二個數據庫。

+0

感謝您的一些額外的部分!我想我更接近一點,我更新了我的問題。 –

+0

謝謝!我同時想到了這一點。我花了一段時間才意識到,即使我使用INSERT指定了列,但它仍在追加,而且我需要第二個數據庫,因爲SQLite會鎖定數據庫。謝謝您的幫助! –