我继续阅读DBI/ODBC
比RODBC
更快,所以我尝试如下:
require(DBI);require(odbc)
con <- DBI::dbConnect(odbc::odbc(), dsn = 'SQLSERVER1', database = 'AcumaticaDB')
我可以成功连接到DSN,但是以下查询:
rs <- dbGetQuery(con, "SELECT * FROM inventoryitem")
dbFetch(rs)
给了我以下错误:
result_fetch中的错误(res @ ptr,n,...): nanodbc / nanodbc.cpp:310:07009:[Microsoft] [SQL Server的ODBC驱动程序13]无效的描述符索引
我做错了什么?
请不要RODBC
解决方案。
谢谢!
答案 0 :(得分:4)
有一种解决方法:
重新排序SELECT
语句,使较长的数据类型(通常是字符串)最后。
如果您有dbply
本身生成的复杂查询,请直接通过show_query()
获取SQL查询。复制粘贴并修改第一个SELECT
语句,使得长数据类型在列表中排在最后。它应该可以工作。
编辑: 在许多情况下,可以通过添加
来重新排序字段%>% select(var1, var2, textvar1, textvar2)
查询。
答案 1 :(得分:3)
rs <- dbGetQuery(con, "SELECT * FROM inventoryitem") dbFetch(rs)
如果inventoryitem
表包含长数据/可变长度列(例如VARBINARY
,VARCHAR
)和简单类型列(例如INT
)的混合,你无法通过ODBC以任意顺序查询它们。
应用程序应确保在选择列表的末尾放置长数据列。
使用ODBC API调用SQLGetData
从数据库中检索长数据
必须在获取行中的其他数据后检索。
这些已知并记录在案的ODBC限制
要从列中检索长数据,应用程序首先调用 SQLFetchScroll或SQLFetch移动到一行并获取数据 绑定列。然后,应用程序调用SQLGetData。
请参阅https://docs.microsoft.com/en-us/sql/odbc/reference/develop-app/getting-long-data
答案 2 :(得分:1)
最近我当然遇到了这个问题。这是我的解决方案。 基本上,您必须首先根据从数据库中获取的列信息对列进行重新排序。列可以混合使用正负类型。因此,先对它们进行排序,然后对它们进行排序即可。
当出现“无效描述符索引”问题时,它与我的数据完美配合。请让我知道它是否也适用。
sqlFetchData <- function(connection, database, schema, table, nobs = 'All') {
#'wrap function to fetch data from SQL Server
#
#@ connection: an established odbc connection
#@ database: database name
#@ schema: a schema under the main database
#@ table: the name of the data table to be fetched.
#@ nobs: number of observation to be fetched. Either 'All' or an integer number.
# The default value is 'All'. It also supports the input of 'all', 'ALL' and
# etc. .
if (is.character(nobs)) {
if (toupper(nobs) == 'ALL') {
obs_text <- 'select'
} else {
stop("nobs could either be 'ALL' or a scalar integer number")
}
} else {
if (is.integer(nobs) && length(nobs) == 1) {
obs_text <- paste('select top ', nobs, sep = '')
} else {
stop("nobs could either be 'ALL' or a scalar integer number")
}
}
initial_sql <- paste("select * from ", database, '.', schema, ".", table,
sep = '')
dbquery <- dbSendQuery(connection, initial_sql)
cols <- dbColumnInfo(dbquery)
dbClearResult(dbquery)
#' sort the rows by query type due to error message:
#' Invalid Descriptor Index
colInfo <- cols
colInfo$type <- as.integer(colInfo$type)
cols_neg <- colInfo[which(colInfo$type < 0), ]
cols_neg <- cols_neg[order(cols_neg[, 2]), ]
cols_pos <- colInfo[which(colInfo$type >= 0), ]
cols_pos <- cols_pos[order(cols_pos[, 2]), ]
cols <- rbind(cols_pos, cols_neg)
add_comma <- "c(cols$name[1], paste(',', cols$name[-1L], sep = ''))"
sql1 <- paste(c(obs_text, eval(parse(text = add_comma))),
collapse = ' ', sep = '')
data_sql <- paste(sql1, ' from ', database, '.', schema, '.', table,
sep = '')
dataFetch <- dbGetQuery(connection, data_sql)[, colInfo$name]
return(dataFetch)
}
答案 3 :(得分:1)
ODBC / DBI在建立连接时将数据库中的字符变量数据类型转换为'ntext'。因此,您需要将R中SQL字符串中的字符变量(例如x)转换为CONVERT(varchar(100),x)。然后dbGetQuery函数应该起作用。
答案 4 :(得分:0)
由于尝试加载时间戳变量而导致此错误。尝试从查询中删除所有时间戳变量。
尝试以下或类似方法。让我知道什么有效,我将更新我的帖子。
require(DBI);require(odbc)
con <- DBI::dbConnect(odbc::odbc(), dsn = 'SQLSERVER1', database = 'AcumaticaDB')
column.types = DBI::dbGetQuery(
con,
'SELECT COLUMN_NAME, DATA_TYPE FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_NAME = "inventoryitem"'
))
sql = paste(c(
'select ',
paste(column.types$COLUMN_NAME[column.types$DATA_TYPE != 'timestamp'], collapse = ', '),
' from inventoryitem'
),
collapse = ''
)
dbFetch(dbGetQuery(con, sql))
答案 5 :(得分:0)
我很高兴很久以前就问过这个问题,但是我设法找到了解决方法。上面的答案使我了解了大部分情况。我遇到的问题是在模式表为-1的nvarchar类型的列中具有CHARACTER_MAXIMUM_LENGTH,我知道这意味着它们是最大长度。
我的解决方案是在INFORMATION_SCHEMA.COLUMNS表中查找相关表,然后适当地重新排列我的字段:
require(DBI);require(odbc)
library(tidyverse)
con <- DBI::dbConnect(odbc::odbc(), dsn = 'SQLSERVER1', database = 'AcumaticaDB')
column.types <- dbGetQuery(con, "SELECT COLUMN_NAME, DATA_TYPE, CHARACTER_MAXIMUM_LENGTH FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_NAME='inventoryitem'")
ct <- column.types %>%
mutate(cml = case_when(
is.na(CHARACTER_MAXIMUM_LENGTH) ~ 10,
CHARACTER_MAXIMUM_LENGTH == -1 ~ 100000,
TRUE ~ as.double(CHARACTER_MAXIMUM_LENGTH)
)
) %>%
arrange(cml) %>%
pull(COLUMN_NAME)
fields <- paste(ct, collapse=", ")
query <- paste("SELECT", fields, "FROM inventoryitems")
tbl(con, sql(query)) %>% head(5)
答案 6 :(得分:-1)
几个月来我也一直在努力解决这个问题。但是,我遇到了一个可能对您也有帮助的解决方案。
简而言之,当某些文本列没有出现在整数/数字列之后时,就会发生此问题。当查询中的列未正确对齐时,将引发错误invalid index
,并且连接可能会冻结。 然后的问题是,我怎么知道查询末尾要输入什么内容?
要确定这一点,通常可以使用class()
或typeof()
检查一列。要从数据库检查此类信息,可以使用查询,例如:
dbColumnInfo(dbSendQuery(con, "SELECT * from schema.table")) # You may not require the schema part...
这将返回一个表,其中包含感兴趣的数据集中的每一列的类型字段。然后,您可以将此表用作索引来对select()
语句进行排序。我的特别困难是表中的type
字段是所有数字!但是,我注意到,当每个带有负数的列放在select语句的末尾时,都可以修复查询,并且可以很好地拉动整个表。例如,我的完整解决方案:
# Create my index of column types (ref to the current order)
index <- dbColumnInfo(dbSendQuery(con, "SELECT * from schema.table"))
index$type <- as.integer(index$type) # B/c they are + and - numbers!
# Create the ref to the table
mySQLTbl <- tbl(con, in_schema("schema", "tablename"))
# Use the select statement to put all the + numbered columns first!
mySQLTbl %>%
select(c(which(index$type>=0),
which(index$type<0)))
关于发生这种情况的原因,我不确定,并且我没有数据访问权限可以在用例中进行更深入的研究