2

我需要创建一个表名包含一些特殊字符的表。我正在使用RSQLite包。我需要创建的表名是port.3.1. 无法使用此名称创建表。所以我将表名更改为[port.3.1]基于SQLite 中的有效表名是什么?.

现在我可以创建表,但我不能向该表插入数据框。我使用的代码如下:

createTable <- function(tableName){
    c <- c(portDate='varchar(20) not null' ,
         ticker='varchar(20)',
         quantities='double(20,10)')
  lite <- dbDriver("SQLite", max.con = 25)
  db <- dbConnect(lite, dbname="sql.db")

  if( length(which(strsplit(toString(tableName),'')[[1]]=='.') ) != 0){ tableName = paste("[",tableName,"]",sep="") } #check whether the portfolio contains special characters or not
  sql <- dbBuildTableDefinition(db, tableName, NULL, field.types = c, row.names = FALSE)
  print(sql)
  dbGetQuery(db, sql)
}
datedPf <- data.frame(date=c("2001-01-01","2001-01-01"), ticker=c("a","b"),quantity=c(12,13))
for(port in c("port1","port2","port.3.1")){
  createTable(port)
  lite <- dbDriver("SQLite", max.con = 25)
  db <- dbConnect(lite, dbname="sql.db")
  if( length(which(strsplit(toString(port),'')[[1]]=='.') ) != 0){ port = paste("[",port,"]",sep="") } #check whether the portfolio contains special characters or not
  dbWriteTable(db,port,datedPf ,append=TRUE,row.names=FALSE)
}

在此示例中,我可以将数据框插入到表port1port2中,但它没有插入到表[port.3.1]中。这背后的原因是什么?我怎么解决这个问题?

4

1 回答 1

3

sqliteWriteTable只需输入该名称并按 Enter 即可查看实现。你会注意到两件事:

[…]
foundTable <- dbExistsTable(con, name)
new.table <- !foundTable
createTable <- (new.table || foundTable && overwrite)
[…]
if (createTable) {
    […]

查看showMethods("dbExistsTable", includeDefs=T)输出,您会看到它使用dbListTables(conn)的将返回您的表名的未引用版本。因此,如果您将引用的表名传递给sqliteWriteTable,那么它将错误地假定您的表不存在,尝试创建它然后遇到错误。如果传递不带引号的表名,则创建语句会出错。

我认为这是 RSQLite 中的一个错误。在我看来,用户传递的 SQL 语句必须正确引用,但是在任何你将表名作为单独参数传递给函数的任何地方,默认情况下都应该不引用该表名,并且应该在从它生成的 SQL 语句中引用该表名。如果名称允许以带引号或不带引号的形式出现会更好,但这主要是为了最大限度地提高可移植性。如果您愿意,可以尝试联系开发人员报告此问题。

您可以解决该问题:

setMethod(dbExistsTable, signature(conn="SQLiteConnection", name="character"),
  function(conn, name, ...) {
    lst <- dbListTables(conn)
    lst <- c(lst, paste("[", lst, "]", sep=""))
    match(tolower(name), tolower(lst), nomatch = 0) > 0
  }
)

这将覆盖dbExistsTableSQLite 连接的默认实现,其版本会检查带引号和不带引号的表名。在此更改之后,"[port.3.1]"作为表名传递将导致foundTable为真,因此 RSQLite 不会尝试为您创建该表。

于 2013-06-04T12:59:35.677 回答