RSQLite类型转换问题

RSQLite类型转换问题,r,sqlite,R,Sqlite,我正试图将SQLite数据库中的一个表写入R数据帧,突然发现了一个让我难堪的问题。下面是我要导入的SQLite表中的前三个条目: 1|10|0|0|0|0|10|10|0|0|0|6|8|6|20000|30000|2012-02-29 21:27:07.239091|2012-02-29 21:28:24.815385|6|80.67.28.161|||||||||||||||||||||||||||||||33|13.4936||t|t|f||||||||||||||||||4|0|0|7|

我正试图将SQLite数据库中的一个表写入R数据帧,突然发现了一个让我难堪的问题。下面是我要导入的SQLite表中的前三个条目:

1|10|0|0|0|0|10|10|0|0|0|6|8|6|20000|30000|2012-02-29 21:27:07.239091|2012-02-29 21:28:24.815385|6|80.67.28.161|||||||||||||||||||||||||||||||33|13.4936||t|t|f||||||||||||||||||4|0|0|7|7|2
2|10|0|0|0|0|0|0|0|2|2|4|5|4|20000|30000|2012-02-29 22:00:30.618726|2012-02-29 22:04:09.629942|5|80.67.28.161|3|7||0|1|3|0|||4|3|4|5|5|5|5|4|5|4|4|0|0|0|0|0|9|9|9|9|9|||1|f|t|f|||||||||||||k|text|l|||-13|0|3|10||2
3|13|2|4|4|4|4|1|1|2|5|6|3|2|40000|10000|2012-03-01 09:07:52.310033|2012-03-01 09:21:13.097303|6|80.67.28.161|2|2||30|1|1|0|||4|2|1|6|8|3|5|6|6|7|6|||||||||||26|13.6336|4|f|t|f|t|f|f|f|f|||||||||some text||||10|1|1|3|2|3
我感兴趣的是第53列到第60列,为了省去您在上面计算的麻烦,它如下所示:

|t|t|f||||||
|f|t|f||||||
|f|t|f|t|f|f|f|f|
正如您所看到的,对于前两个条目,只有前三列不为NULL,而对于第三个条目,所有八列都有分配给它们的值

下面是这些列的SQLite表信息

sqlite> PRAGMA table_info(observations);
0|id|INTEGER|1||1
** snip **
53|understanding1|boolean|0||0
54|understanding2|boolean|0||0
55|understanding3|boolean|0||0
56|understanding4|boolean|0||0
57|understanding5|boolean|0||0
58|understanding6|boolean|0||0
59|understanding7|boolean|0||0
60|understanding8|boolean|0||0
** snip **
现在,当我试着读入R时,同样的专栏最终会变成:

> library('RSQLite')
> con <- dbConnect("SQLite", dbname = 'db.sqlite3))
> obs <- dbReadTable(con,'observations')
> obs[1:3,names(obs) %in% paste0('understanding',1:8)]
  understanding1 understanding2 understanding3 understanding4 understanding5 understanding6 understanding7
1              t              t              f             NA             NA             NA             NA
2              f              t              f             NA             NA             NA             NA
3              f              t              f              0              0              0              0
  understanding8
1             NA
2             NA
3              0
RSQLite是否会在第一个条目中的相应列中看到t和f作为值时,将前三列设置为字符类型,但会使用numeric,因为在这些列中,第一个条目恰好为NULL


如果这真的发生了,有没有办法解决这个问题,将所有这些列转换成字符,或者更好的是,转换成逻辑?

下面的内容很粗糙,但它是有效的:

# first make a copy of the DB and work with it instead of changing
# data in the original
original_file <- "db.sqlite3"
copy_file <- "db_copy.sqlite3"
file.copy(original_file, copy_file) # duplicate the file
con <- dbConnect("SQLite", dbname = copy_file) # establish a connection to the copied DB

# put together a query to replace all NULLs by 'NA' and run it
columns <- c(paste0('understanding',1:15))
columns_query <- paste(paste0(columns,' = IfNull(',columns,",'NA')"),collapse=",")
query <- paste0("UPDATE observations SET ",columns_query)
dbSendQuery(con, query)

# Now that all columns have string values RSQLite will infer the 
# column type to be `character`
df <- dbReadTable(con,'observations') # read the table
file.remove(copy_file) # delete the copy

# replace all 'NA' strings with proper NAs
df[names(df) %in% paste0('understanding',1:15)][df[names(df) %in% paste0('understanding',1:15)] == 'NA'] <- NA
# convert 't' to boolean TRUE and 'f' to boolean FALSE
df[ ,names(df) %in% paste0('understanding',1:15)] <- sapply( df[ ,names(df) %in% paste0('understanding',1:15)], function(x) {x=="t"} )

我对SQLite的了解是有限的,但我对如何将字符t和`f存储在SQLite的布尔列中感到困惑。我的理解是SQLite没有本机布尔类型,它只是将它们存储为整数0和1。此外,列类型是不强制的,因此如果将文本插入到布尔字段中,SQLite将转换列的存储模式。例如,我对SQLite也不是专家,我不知道列类型不是强制的。整个数据库来自RubyonRails web应用程序,我几乎不得不接受它的原样。但是,如果问题是列类型没有强制执行,并且RSQLite显然不只是使用列类型的R等价物,那么RSQLite如何推断要为每个列分配什么类,以及是否有任何方式影响该推断?我不确定;我在RSQLite的文档中找不到描述,但真正的答案可能隐藏在DBI包的文档中。网络上的一些人肯定知道RSQLite如何进行类型转换的细节。但在你问之前,我会仔细检查你的数据库,绝对确保在一列中t和f的值都变成了NA和0,因为这听起来很奇怪。我只是再次检查了一下,我能说的最好,确实是这样。谢谢你的指点。我将和R-SIG-DBM上的人讨论我的怀疑,关于如何进行打字确实是正确的,所以我一直在尝试按照前面链接的文章的建议,简单地用“NA”替换这些列中的每个空值,然后从那里开始。然而,我希望这样做,SQLite数据库不会永久改变。有没有办法运行INSERT查询来替换NULL,将表读入R,然后还原INSERT?
# first make a copy of the DB and work with it instead of changing
# data in the original
original_file <- "db.sqlite3"
copy_file <- "db_copy.sqlite3"
file.copy(original_file, copy_file) # duplicate the file
con <- dbConnect("SQLite", dbname = copy_file) # establish a connection to the copied DB

# put together a query to replace all NULLs by 'NA' and run it
columns <- c(paste0('understanding',1:15))
columns_query <- paste(paste0(columns,' = IfNull(',columns,",'NA')"),collapse=",")
query <- paste0("UPDATE observations SET ",columns_query)
dbSendQuery(con, query)

# Now that all columns have string values RSQLite will infer the 
# column type to be `character`
df <- dbReadTable(con,'observations') # read the table
file.remove(copy_file) # delete the copy

# replace all 'NA' strings with proper NAs
df[names(df) %in% paste0('understanding',1:15)][df[names(df) %in% paste0('understanding',1:15)] == 'NA'] <- NA
# convert 't' to boolean TRUE and 'f' to boolean FALSE
df[ ,names(df) %in% paste0('understanding',1:15)] <- sapply( df[ ,names(df) %in% paste0('understanding',1:15)], function(x) {x=="t"} )