简体   繁体   English

R DBI ODBC 错误:nanodbc/nanodbc.cpp:3110:07009:[Microsoft][ODBC Driver 13 for Z9778840A0100CB30C982876741

[英]R DBI ODBC error: nanodbc/nanodbc.cpp:3110: 07009: [Microsoft][ODBC Driver 13 for SQL Server]Invalid Descriptor Index

I continue to read the DBI/ODBC is faster than RODBC , so I tried as follows:我继续阅读DBI/ODBCRODBC更快,所以我尝试如下:

require(DBI);require(odbc)
con <- DBI::dbConnect(odbc::odbc(), dsn = 'SQLSERVER1', database = 'AcumaticaDB')

I can make a successful connection to the DSN, but the following query:我可以成功连接到 DSN,但查询如下:

rs <- dbGetQuery(con, "SELECT * FROM inventoryitem")
dbFetch(rs)

gives me the following error:给我以下错误:

Error in result_fetch(res@ptr, n, ...): nanodbc/nanodbc.cpp:3110: 07009: [Microsoft][ODBC Driver 13 for SQL Server]Invalid Descriptor Index result_fetch(res@ptr, n, ...) 中的错误:nanodbc/nanodbc.cpp:3110:07009:[Microsoft][ODBC Driver 13 for SQL Server]无效的描述符索引

What am I doing wrong?我究竟做错了什么? Please, no RODBC solutions.请不要RODBC解决方案。 Thanks!谢谢!

I have also been struggling with this issue for several months.我也一直在为这个问题苦苦挣扎了几个月。 However, I have come across a solution that may help you as well.但是,我遇到了一个也可以帮助您的解决方案。

In a nutshell, the issue occurs when certain text columns do not appear after integer/numeric columns.简而言之,当某些文本列没有出现在整数/数字列之后时,就会出现问题。 When the columns are not aligned properly in the query, an error of invalid index is thrown and your connection may freeze.当查询中的列没有正确对齐时,会抛出invalid index的错误,并且您的连接可能会冻结。 The issue then is, how do I know what to put at the end of my query?那么问题是,我怎么知道在查询的末尾放什么?

To determine this, one could typically examine a column using class() or typeof() .要确定这一点,通常可以使用class()typeof()检查列。 To examine such information from the database, you can use a query such as:要检查数据库中的此类信息,您可以使用以下查询:

dbColumnInfo(dbSendQuery(con, "SELECT * from schema.table")) # You may not require the schema part...

This will return a table with a type field for every column in the data-set of interest.这将为感兴趣的数据集中的每一列返回一个带有类型字段的表。 You can then use this table as an index to sort the select() statement.然后,您可以使用该表作为索引来对select()语句进行排序。 My particular difficulty is that the type field in the table was all numbers!我的特别困难是表中的type字段都是数字! However, I noticed that every column with a negative number, when placed at the end of the select statement, fixed my query and I could pull the whole table just fine.但是,我注意到每个带有负数的列放在 select 语句的末尾时,修复了我的查询,我可以很好地拉出整个表。 For example, my full solution :例如,我的完整解决方案

# 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)))

As for reason for why this occurs, I am not sure and I do not have the data access privileges to dig much deeper in my use-case至于发生这种情况的原因,我不确定,我没有数据访问权限在我的用例中进行更深入的挖掘

I appreciate that this question was asked a long time ago, but I've managed to find a workaround.我很感激这个问题很久以前就被问到了,但我已经设法找到了解决方法。 The answers above got me most of the way there.上面的答案让我大部分时间都在那里。 The problem I had was with columns of type nvarchar that had a CHARACTER_MAXIMUM_LENGTH in the schema table of -1, which I understand means they are the maximum length possible.我遇到的问题是 nvarchar 类型的列在 -1 的架构表中具有 CHARACTER_MAXIMUM_LENGTH,我理解这意味着它们是可能的最大长度。

My solution was to lookup the relevant table in the INFORMATION_SCHEMA.COLUMNS table and then rearrange my fields appropriately:我的解决方案是在 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)
rs <- dbGetQuery(con, "SELECT * FROM inventoryitem") dbFetch(rs)

If inventoryitem table contains mix of long data/variable-length columns (eg. VARBINARY , VARCHAR ) and columns of simple types (eg. INT ), you can not query them in arbitrary order via ODBC.如果inventoryitem表包含长数据/可变长度列(例如VARBINARYVARCHAR )和简单类型列(例如INT )的混合,则不能通过 ODBC 以任意顺序查询它们。

Applications should make sure to place long data columns at the end of the select list.应用程序应确保在选择列表的末尾放置长数据列。

Long data is retrieved from database using ODBC API call SQLGetData and it has to be retrieved after the other data in the row has been fetched.长数据是使用 ODBC API 调用SQLGetData从数据库中检索的,并且必须在获取行中的其他数据后检索。

These are known and documented ODBC restrictions这些是已知并记录在案的 ODBC 限制

To retrieve long data from a column, an application first calls SQLFetchScroll or SQLFetch to move to a row and fetch the data for bound columns.要从列中检索长数据,应用程序首先调用 SQLFetchScroll 或 SQLFetch 以移动到一行并获取绑定列的数据。 The application then calls SQLGetData.然后应用程序调用 SQLGetData。

See https://docs.microsoft.com/en-us/sql/odbc/reference/develop-app/getting-long-data请参阅https://docs.microsoft.com/en-us/sql/odbc/reference/develop-app/getting-long-data

There is a workaround:有一个解决方法:

Reorder your SELECT statements such that longer datatypes (typically strings) are last.重新排序您的SELECT语句,以便将较长的数据类型(通常是字符串)放在最后。

If you have a complex query that is generated by dbplyr itself, then get the SQL query directly via show_query() .如果您有一个由dbplyr本身生成的复杂查询,则直接通过show_query()获取 SQL 查询。 Copy-paste and modify the first SELECT statement such that long datatypes are last in the list.复制粘贴并修改第一个SELECT语句,使长数据类型在列表的最后。 It should then work.然后它应该工作。

EDIT: in many cases it is possible to reorder the fields by adding this to the query:编辑:在许多情况下,可以通过将其添加到查询中来重新排序字段:

%>% select(var1, var2, textvar1, textvar2)

I certainly encountered this problem recently.我最近肯定遇到了这个问题。 Here is my solution.这是我的解决方案。 Basically you have to reorder columns based on the column information fetched from the database first.基本上,您必须首先根据从数据库中获取的列信息对列重新排序。 Columns could mix with positive and negative types.列可以混合使用正类型和负类型。 So sorting them with positive first, then negative will do the trick.所以先用正面对它们进行排序,然后对它们进行排序就可以了。

It works perfectly with my data when having "Invalid Descriptor Index" issue.当出现“无效的描述符索引”问题时,它与我的数据完美配合。 Please let me know whether it works for you too.请让我知道它是否也适合您。

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

ODBC/DBI convert character variable data type in the database into 'ntext' while making the connection. ODBC/DBI 在建立连接时将数据库中的字符变量数据类型转换为“ntext”。 So, you need to convert your character variables (say x) in the SQL string in R as CONVERT(varchar(100),x).因此,您需要将 R 中 SQL 字符串中的字符变量(例如 x)转换为 CONVERT(varchar(100),x)。 Then dbGetQuery function should work.然后 dbGetQuery 函数应该可以工作。

I got this error as a result of trying to load in a timestamp variable.由于尝试加载时间戳变量,我收到此错误。 Try removing any timestamp variables from your query.尝试从您的查询中删除任何时间戳变量。

Try the below or similar.尝试以下或类似的。 Let me know what works and I'll update my post.让我知道什么有效,我会更新我的帖子。

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

This error can also occur if you have a field of type geometry .如果您有一个geometry类型的字段,也会发生此错误。 You should SELECT AS and use a spatial method to convert to WKT before pulling into a data.table.在拉入 data.table 之前,您应该SELECT AS并使用空间方法转换为 WKT。 See below, where you know that Shape is a field of type geometry .见下文,您知道Shape是一个geometry类型的字段。 By using the spatial method .STAsText() it converts it to Well-Known Text (WKT) format, which R can work with more easily.通过使用空间方法.STAsText()它将其转换为众所周知的文本 (WKT) 格式,R 可以更轻松地使用这种格式。

library(sf)
library(tidyverse)

query <- "
SELECT company, revenue, address, Shape.STAsText() AS ShapeWKT
FROM businesses_table
"

results <- dbFetch(dbSendQuery(con, query)) %>%
  filter(!is.na(ShapeWKT)) %>%
  mutate(Shape = st_as_sfc(ShapeWKT)) %>%
  select(-ShapeWKT) %>%
  st_as_sf()

I built a more complex function that allows you to specify a db connection, table name, a field exception (defaults to return all fields EXCEPT those in exception field), a WHERE clause to filter your query, and specify a spatial field name, since it varies from table to table (ie, could be Shape could be Geo , etc.).我构建了一个更复杂的函数,它允许你指定一个数据库连接、表名、一个字段异常(默认返回所有字段,除了exception字段中的字段)、一个 WHERE 子句来过滤你的查询,并指定一个空间字段名称,因为它因表而异(即,可能是Shape可能是Geo等)。

spatial_query <- function(con, tablename, 
                          exception = "", 
                          wherefilter = "", 
                          spatialfieldname = "Shape",
                          spatial = TRUE){
  ## Get last element (table name) from explicit table name
  tmp <- strsplit(tablename, "[.]")[[1]]
  tablename_short <- tmp[length(tmp)]
  
  fields <- dbListFields(con, tablename_short)
  
  if(spatial){
    fields_to_grab <- fields[!(fields %in% c(exception, spatialfieldname))]
    ## TODO adjust query to be responsive to Shape
    qstring <- paste0('SELECT ', paste(fields_to_grab, collapse = ", "), ', ', spatialfieldname, '.STAsText() AS ShapeWKT FROM ', tablename, ' ', wherefilter)
    cat(paste("Sending following SQL statement:", qstring, "\n", sep = "\n"))
    ret <- dbFetch(dbSendQuery(con, qstring)) %>%
      filter(!is.na(ShapeWKT)) %>%
      mutate(Shape = st_as_sfc(ShapeWKT)) %>%
      select(-ShapeWKT) %>%
      st_as_sf()
  }
  
  else{
    fields_to_grab <- fields[!(fields %in% exception)]
    qstring <- paste0('SELECT ', paste(fields_to_grab, collapse = ", "),' FROM ', tablename, ' ', wherefilter)
    cat(paste("Sending following SQL statement:", qstring, "\n", sep = "\n"))
    ret <- dbFetch(dbSendQuery(con, qstring))
  }
  
  return(ret)
}

Maybe I missed someone else adding this, but I had this exact same error, read through this string and tried several elaborate things like reordering columns, and didn't know how to solve it for several months.也许我错过了其他人的添加,但是我遇到了完全相同的错误,通读了这个字符串并尝试了一些复杂的事情,比如重新排序列,并且几个月来不知道如何解决它。 Then, I found out that I just had to upgrade to the most recent SQL Server Driver for my Windows 10 and change the driver in my connection string, and the problem was solved.然后,我发现我只需升级到适用于我的 Windows 10 的最新 SQL Server 驱动程序并更改连接字符串中的驱动程序,问题就解决了。

In case someone else comes across this SO question....万一其他人遇到这个SO问题....

I also was having a problem with the using the SELECT * FROM table statement with a setup like this:我在使用SELECT * FROM table语句时也遇到了问题,设置如下:

library(odbc)
library(DBI)

con <- DBI::dbConnect(odbc::odbc(),
                      Driver   = "SQL Server",
                      Server   = "CorporateServer",
                      Database = "DB_of_Interest",
                      Port     = 1433)

sql <- "SELECT TOP (10) *
  FROM [DB_of_Interest].[dbo].[tb_of_interest]"

dbGetQuery(con, sql)

Which generated this error:这产生了这个错误:

Error in result_fetch(res@ptr, n) : 
  nanodbc/nanodbc.cpp:3069: 07009: [Microsoft][ODBC SQL Server Driver]Invalid Descriptor Index 
Warning message:
In dbClearResult(rs) : Result already cleared

My Solution我的解决方案

After looking at RStudio -- Connect to a Database , I looked to see what other drivers might be available to me:在查看RStudio -- Connect to a Database之后,我查看了哪些其他驱动程序可供我使用:

sort(unique(odbcListDrivers()[[1]]))

 [1] "Amazon Redshift (x64)"                                 
 [2] "Hortonworks Hive ODBC Driver"                          
 [3] "Hortonworks Spark ODBC Driver"                         
 [4] "Microsoft Access Driver (*.mdb, *.accdb)"              
 [5] "Microsoft Access Text Driver (*.txt, *.csv)"           
 [6] "Microsoft Excel Driver (*.xls, *.xlsx, *.xlsm, *.xlsb)"
 [7] "MySQL ODBC 5.3 ANSI Driver"                            
 [8] "MySQL ODBC 5.3 Unicode Driver"                         
 [9] "ODBC Driver 17 for SQL Server"                         
[10] "PostgreSQL ANSI(x64)"                                  
[11] "PostgreSQL Unicode(x64)"                               
[12] "Simba ODBC Driver for Google BigQuery"                 
[13] "SQL Server"                                            
[14] "SQL Server Native Client 11.0"      

And #9 caught my eye: ODBC Driver 17 for SQL Server . #9 引起了我的注意: ODBC Driver 17 for SQL Server I went into the Windows Control Panel, and set up a new ODBC Data Source using that particular driver (in my case, I named it "Buyer Central 2" and I have Integrated Windows authentication, so no username/password), and then revised my R code to be:我进入 Windows 控制面板,并使用该特定驱动程序设置了一个新的 ODBC 数据源(在我的情况下,我将其命名为“Buyer Central 2”并且我已经集成了 ZAEA23489CE3AA9B6406EBB28E0CDA4,然后修改了身份验证,所以没有//我的 R 代码为:

con2 <- DBI::dbConnect(odbc::odbc(),
                       dsn = "Buyer Central 2")

dbGetQuery(con2, sql) 

Now the sql statement with the glob (*) works for me.现在带有 glob (*) 的 sql 语句对我有用。

Alternative that doesn't work (for me)不起作用的替代方案(对我来说)

I thought and tried to use the other ODBC driver without the formal setup in the data source administrator:我想并尝试在数据源管理员没有正式设置的情况下使用其他 ODBC 驱动程序:

con3 <- DBI::dbConnect(odbc::odbc(),
                      Driver   = "ODBC Driver 17 for SQL Server",
                      Server   = "CorporateServer",
                      Database = "DB_of_Interest",
                      Port     = 1433)

But that line fails for me with the following:但是这条线对我来说失败了,原因如下:

Error: nanodbc/nanodbc.cpp:1021: 01S00: [Microsoft][ODBC Driver 17 for SQL Server][SQL Server]Login failed for user ''.  [Microsoft][ODBC Driver 17 for SQL Server]Invalid connection string attribute 

I searched for a reason why it works when set up in admin tools, but not as above, and found comments related to SQL Server 2014 not working with this driver due to SSL issues, but I checked my version and I'm using SQL Server 2016... so not that. I searched for a reason why it works when set up in admin tools, but not as above, and found comments related to SQL Server 2014 not working with this driver due to SSL issues, but I checked my version and I'm using SQL Server 2016...所以不是这样。 Curious why it doesn't work this way, but the above solution does work.好奇为什么它不能以这种方式工作,但上述解决方案确实有效。

I recently faced the same problem.我最近遇到了同样的问题。 The short and the easiest solution is to find the column info first and place the column at the end with max values(suppose varchar(max) and or varbinary(max) ).简短且最简单的解决方案是首先找到列信息,然后将列放在具有最大值的末尾(假设varchar(max) 和或 varbinary(max) )。 Try the example below.试试下面的例子。

With Error有错误

library(DBI)
library(ODBC)
myquery<- dbGetQuery(con,"SELECT * FROM MYTABLE")

Error in Result_fetch....:  Invalid Descriptor Index

Solution解决方案

dbcolumnInfo(dbSendWuery(con,"SELECT * FROM MYTABLE")

dbcolumninfo() 的输出

As you can see the datatype for DateTimeSampled is varchar(max).如您所见, DateTimeSampled的数据类型是 varchar(max)。 Place this data column at the end while retrieving the columns of MYTABLE using following query.使用以下查询检索MYTABLE的列时,将此数据列放在末尾。

myquery<- dbGetQuery(con,"SELECT [PROCHI],[hb_extract],
[QuantityValue],[QuantityUnit],[Interpretation],
[LabNumber],[LocalClinicalCodeValue],[DateTimeSampled]
FROM MYTABLE")

Enjoy SQL with R享受 SQL 与 R

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 result_fetch(res@ptr, n)&#39;: nanodbc/nanodbc.cpp:2966: 07009: [Microsoft] [ODBC Driver 13 for SQL Server]无效的描述符索引 - result_fetch(res@ptr, n)': nanodbc/nanodbc.cpp:2966: 07009: [Microsoft][ODBC Driver 13 for SQL Server]Invalid Descriptor Index 从 R 工作室连接到 SQL 服务器:“错误:nanodbc/nanodbc.cpp:983:00000: [unixODBC][Driver Manager]无法打开 lib 'driver': 找不到文件” - Connecting to SQL Server from R studios: "Error: nanodbc/nanodbc.cpp:983: 00000: [unixODBC][Driver Manager]Can't open lib 'driver' : file not found" 不使用DSN时出现R ODBC nanodbc错误 - R ODBC nanodbc error when not using DSN R 与 SQL Server 2016 错误“[Microsoft][ODBC 驱动程序管理器] 未找到数据源名称且未指定默认驱动程序” - R with SQL server 2016 error “[Microsoft][ODBC Driver Manager] Data source name not found and no default driver specified” SQL Server的DBI或odbc软件包 - DBI or odbc package for SQL server 如何使用 R 中的 ODBC 和 DBI 连接到 MS SQL 服务器 - How to connect to MS SQL Server using ODBC and DBI in R R ODBC DBI 错误:数据库不存在 - R ODBC DBI error: database does not exist 使用Informix驱动程序在R中进行ODBC连接时出现SQL查询错误 - SQL query error with ODBC connection in R using Informix driver 从 MS SQL 2012 odbc 连接读取表时描述符索引无效 - Invalid Descriptor Index when reading table from MS SQL 2012 odbc connection 使用ODBC从R查询SQL Server数据库时出现无效的对象名称时出错 - Invalid object name Error when querying SQL Server Database from R using ODBC
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM