2013-06-04 72 views
2

我需要创建一个表名有一些特殊字符的表。我正在使用RSQLite包。我需要创建的表名是port.3.1。用这个名字创建表是不可能的。所以我根据What are valid table names in SQLite?将表名改为[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]。这背后的原因是什么?我怎么解决这个问题?

回答

3

看看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 
    } 
) 

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

+0

太棒了..谢谢你的时间和精力..非常有价值的信息给我......再次感谢.. :) –