与https://stackoverflow.com/a/33284035/3358272相关,我发现从SQL Server(2014)中提取数据的行为不一致。
library(RODBC)
sqlQuery(.conn, "CREATE TABLE r2test ( [mychar] [NVARCHAR](16), [mynum] [FLOAT])")
# character(0)
sqlQuery(.conn, "INSERT INTO r2test (mychar,mynum) VALUES ('1',3.141593),('2',6.283185)")
character(0)
str(sqlQuery(.conn, "SELECT * FROM r2test", stringsAsFactors = FALSE))
# 'data.frame': 2 obs. of 2 variables:
# $ mychar: int 1 2
# $ mynum : num 3.14 6.28
在该示例中,我们看到了不期望的行为:mychar
的字符在内部转换为整数。根据前面提到的SO答案,as.is
选项会使这个失败,但是还有一个不幸的副作用,即强制将十进制表示的浮点数转换为字符串:
str(sqlQuery(.conn, "SELECT * FROM r2test", stringsAsFactors = FALSE, as.is = TRUE))
# 'data.frame': 2 obs. of 2 variables:
# $ mychar: chr "1" "2"
# $ mynum : chr "3.1415929999999999" "6.2831849999999996"
如果mychar
中至少有一个实际上不是整数可用的,那么一切都很好:
sqlQuery(.conn, "INSERT INTO r2test (mychar,mynum) VALUES ('a',9.424778)")
# character(0)
str(sqlQuery(.conn, "SELECT * FROM r2test", stringsAsFactors = FALSE))
# 'data.frame': 3 obs. of 2 variables:
# $ mychar: chr "1" "2" "a"
# $ mynum : num 3.14 6.28 9.42
不幸的是,数据模型不支持任意添加某些内容来鼓励这种行为(或者我还没有想到这样做的好方法)。数据模型使得mychar
的值包括01
和1
,这些值在字符方面是不同的。我找到的唯一解决方法是使用as.is = TRUE
,这将要求我as.numeric
所有相关列,这既繁琐又(理论上)不必要的工作。
由于文档建议需要设置DBMSencoding
,我检查了当前编码(由https://stackoverflow.com/a/5182469/3358272帮助):
sqlQuery(.conn, "SELECT SERVERPROPERTY('Collation')")
# 1 SQL_Latin1_General_CP1_CI_AS
我尝试过使用(用于踢):DBMSencoding="latin1"
,DBMSencoding="UTF-8"
,并明确表示默认DBMSencoding=""
但行为没有变化。
如何鼓励不过度胁迫数据类型的行为?
目前在ubuntu上使用R-3.2.5和RODBC-1.3.13。
答案 0 :(得分:8)
如果我理解正确,我认为如果您正在寻找,
str(sqlQuery(
.conn,
"SELECT * FROM r2test",
stringsAsFactors = FALSE,
as.is = c(TRUE, FALSE)
))
#'data.frame': 2 obs. of 2 variables:
# $ mychar: chr "1" "2"
# $ mynum : num 3.14 6.28
其中as.is
被指定为逻辑向量(必须与结果集中的列数具有相同的长度)。公平地说,这并不是很清楚。 sqlQuery
的手册页仅引用as.is
中的read.table
参数,其中指出:
请注意,as.is是按列(而不是每个变量)指定的 包括行名称列(如果有)和任何列 跳过。
这种方法的缺点是您需要事先知道要转换哪些列以及哪些列不转换。就个人而言,我没有看到为什么默认行为不仅仅是将SQL字符类型映射到R字符类型,SQL数字类型映射到R数字类型等,但也许有一个很好的理由在后端。自动将'1'
,'2'
,...转换为整数不对我来说似乎是一个“功能”。