我需要创建一个表名,其中包含一些特殊字符。我正在使用RSQLite
包。我需要创建的表名是port.3.1
。无法使用此名称创建表。因此,我根据What are valid table names in SQLite?将表名更改为[port.3.1]
。
现在我可以创建表,但是我无法将数据帧插入到该表中。 我使用的代码如下:
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)
}
在此示例中,我可以将数据框插入表port1
和port2
,但不会在表[port.3.1]
上插入。这背后的原因是什么?我该如何解决这个问题?
答案 0 :(得分:3)
只需输入该名称并按Enter即可查看sqliteWriteTable
实施。你会注意到两件事:
[…]
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
}
)
这将覆盖SQLite连接的dbExistsTable
的默认实现,其中的版本检查引用和不引用的表名。在此更改之后,将"[port.3.1]"
作为表名称传递将导致foundTable
为真,因此RSQLite将不会尝试为您创建该表。