DBI dbWriteTable

Posted

技术标签:

【中文标题】DBI dbWriteTable【英文标题】: 【发布时间】:2017-01-06 19:46:04 【问题描述】:

我非常喜欢 DBI 的 dbWriteTable 函数(我通常使用 RSQLite 或 ROracle 作为后端)。

我使用该功能导入大量 Excel 电子表格,问题是如果这些电子表格是长期创建的,则会添加/删除列更改或将名称从一个文档更改为另一个文档。

所以我的问题是,有没有人有一种相对快速的方法可以将数据添加到数据库,而不必完美匹配归档列表?

这是我使用的示例脚本

require(RSQLite)
require(readxl)

# Create database file
conn <- dbConnect(drv=SQLite(),dbname = "path to database")

# Define import function

excel2sqltable <- function(conn, file, table) 
  source.df <-  read_excel(path=file,col_names = TRUE) %>%
  cbind("SourceFile" = file, .)

  names(source.df) <- source.df %>%
    data.frame(check.names = TRUE) %>%
    gsub("[.]",x=names(.),replacement="_")

  print(paste("Importing ", file))

  setOldClass(c("tbl_df", "data.frame"))
  dbWriteTable(conn = conn, name = table, value = source.df, append=TRUE)

有了这个功能,我可以做到: sapply(list.files(),FUN = function(x)excel2sqltable(conn,x,"Imports"))

【问题讨论】:

不清楚您在这里要做什么。您是否要跳过有关命名source.df 列的部分?还是您在谈论脚本的dbWriteTable 部分? 我猜怎么升级这个脚本来动态创建字段,这样dbWriteTable 不会引发错误Columns NewColumn not found 在数据库中查询单行,并设置列名来匹配?我必须查看文档以查看是否有 DBI 函数仅用于返回表的列名... 如果您的表已经在数据库中,您可以使用cols &lt;- dbListFields(conn, 'Imports') 获取其列名,然后您实际上可以将这些名称用于导入的数据 (source.df):source.df &lt;- read_excel(path=file,col_names = cols, skip = 1) 对,但是当 source.df 有一个额外的列时,我们将其称为 NewColumn 然后 dbWriteTable 将引发错误 Columns NewColumn not found。因此,我需要转到数据库,并手动将 ALTER TABLE 包含在 NewColumn 中。我想避免手动执行此操作,我想自动化该部分。 【参考方案1】:

您可以以此为指导:

library(RSQLite)

sqlite_conn <- dbConnect(drv = SQLite(),dbname = 'data_dump.sqlite')

excel2sqltable <- function(conn, file, table) 
  source.df <-  readxl::read_excel(path=file,col_names = TRUE) %>%
    cbind("SourceFile" = file, .)

  names(source.df) <- source.df %>%
    data.frame(check.names = TRUE) %>%
    gsub("[.]",x=names(.),replacement="_")

  if(!dbExistsTable(conn, table)) 
    dbWriteTable(conn = conn, name = table, value = source.df)
   else 
    # Get both dataframe columns and table columns
    df_cols <- colnames(source.df)
    tbl_cols <- dbListFields(conn, table)

    # Check if there are columns in the dataframe
    # that are not in the destination table
    # Loop through the missing columns and add
    # them to the database table
    if (length(setdiff(df_cols, tbl_cols)) > 0) 
      missing_cols <- setdiff(df_cols, tbl_cols)
      for (col_name in missing_cols) 
        dbSendStatement(conn, sprintf('ALTER TABLE %s ADD %s VARCHAR', table, col_name))
      
    

    setOldClass(c("tbl_df", "data.frame"))


    dbWriteTable(conn = conn, name = table, value = source.df, append=TRUE)
  


lapply(list.files(), function(x) 
  excel2sqltable(sqlite_conn, x, "Imports")
)
dbDisconnect(sqlite_conn)

我希望它有一个目的。

【讨论】:

以上是关于DBI dbWriteTable的主要内容,如果未能解决你的问题,请参考以下文章

Perl DBI - 使用多个语句运行 SQL 脚本

ruby 1.8.7 和 2.1 之间的 DBI 行/委托行为

为啥回滚方法不能用于 DBI 句柄?

DBI:评估中的引发错误

如何使用 DBI 从数据库中读取中文文本?

Perl/DBI/FreeTDS/SQLAzure 一些插入被忽略