如何做"选择*来自"使用odbc进行查询

时间:2018-05-21 19:47:01

标签: r sql-server odbc

我在R中使用odbc package,我有一个SQL Server数据库,其表格的Name列为nvarchar(max)PublishStatus }列是一个整数。

此代码无效:

library(odbc)
library(DBI)
library(tidyverse)
con_string="Driver=ODBC Driver 11 for SQL Server;Server=myServer; Database=MyDatabase; trusted_connection=yes"
con=dbConnect(odbc::odbc(), .connection_string =con_string)
query="select * from MyTable"
result=NULL
result=dbSendQuery(con,query) %>% dbFetch
head(result)

它只会产生错误消息

  

result_fetch中的错误(res @ ptr,n,...):     nanodbc / nanodbc.cpp:2890:07009:[Microsoft] [SQL Server的ODBC驱动程序11]无效的描述符索引

如果我再次尝试查询,我会收到一条不同的错误消息,而且我可以告诉你如果没有关闭R并重新开启就无法恢复:

  

错误:'选择PublishStatus,来自MyTable的名称'     nanodbc / nanodbc.cpp:1587:HY000:[Microsoft] [用于SQL Server的ODBC驱动程序11]连接忙于另一个命令的结果

因为R和R的odbc都非常有名,所以在这个软件包中很难发现google错误。在this SO中,似乎列的顺序很重要,并且它需要在查询中首先指定整数列。

所以这是有效的

query="select PublishStatus,Name from MyTable"
result=NULL
result=dbSendQuery(con,query) %>% dbFetch
head(result)

但这不是:

query="select Name,PublishStatus from MyTable"
result=NULL
result=dbSendQuery(con,query) %>% dbFetch
head(result)

并且select *查询没有。

所以我的问题是:

  1. 有没有办法让它可以select *查询?
  2. 当我收到Invalid Descriptor Index错误时,有没有办法在不重新启动R的情况下恢复?
  3. 如果没有,这似乎是这个包的一个非常奇怪的交易破坏者。

    编辑:使用较旧的RODBC库,即使使用相同的ODBC驱动程序,它也没有此缺陷。这适用于select * from次查询,并不关心列的顺序

    library(RODBC)
    con=odbcDriverConnect(ConnectionString_Hemonc)  
    result=sqlQuery(con,query,stringsAsFactors=FALSE)
    close(con)
    head(result)
    

    我以前放弃了RODBC因为it is unable (in practice) to write data to a database, as I discovered here

    看起来发生的事情是他们构建odbc以更快地读取数据,这样做的副作用是它现在对于读取数据的顺序非常挑剔。不幸的是,这会破坏我的用例 - 我不能要求只知道基本SQL的人使用一种将完全有效的SQL视为无效的工具。

    我猜它RODBC用于读取数据,odbc用于写入数据。让人惊讶。

    编辑2 :我在连接字符串中尝试了ODBC Driver 13 for SQL Server而不是ODBC Driver 11并且它没有解决问题,但至少它的速度要快得多

1 个答案:

答案 0 :(得分:0)

我希望下面的代码和文章对您有所帮助。 Getting Data From Excel and SQL Server using ODBC

set-psdebug -strict
$ErrorActionPreference = "stop" 

$ExcelFilePath='MyPath\pubs.xlsx' #the full path of the excel workbook
if (!(Test-Path $ExcelFilePath))
 {
 Write-Error "Can't find '$($ExcelFilePath)'. Sorry, can't proceed because of this"
 exit
 }

try {
$Connection = New-Object system.data.odbc.odbcconnection
$Connection.ConnectionString = 'Driver={Microsoft Excel Driver (*.xls, *.xlsx, *.xlsm, *.xlsb)};DBQ='+$ExcelFilePath+'; Extended Properties="Mode=ReadWrite;ReadOnly=false; HDR=YES"' 
$Connection.Open()
}
catch
{
 $ex = $_.Exception
 Write-Error "whilst opening connection to $ExcelFilePath : Sorry, can't proceed because of this"
 exit
}

try { 
$Query = New-Object system.data.odbc.odbccommand
$Query.Connection = $connection
$Query.CommandText = @'
SELECT title, SUM(qty) AS sales,
 COUNT(*) AS orders
 FROM [titles$] t
 INNER JOIN [sales$] s ON t.title_id=s.title_id
 WHERE title like '%?'
 GROUP BY title
 ORDER BY SUM(qty) DESC
'@ 

$Reader = $Query.ExecuteReader([System.Data.CommandBehavior]::SequentialAccess) #get the datareader and just get the result in one gulp
}
catch
{
 $ex = $_.Exception
 Write-Error "whilst executing the query '$($Query.CommandText)' $ex.Message Sorry, but we can't proceed because of this!"
 $Reader.Close()
 $Connection.Close()
 Exit;
}

Try
{
$Counter = $Reader.FieldCount #get it just once
$result=@() #initialise the empty array of rows
 while ($Reader.Read()) {
 $Tuple = New-Object -TypeName 'System.Management.Automation.PSObject'
 foreach ($i in (0..($Counter - 1))) {
 Add-Member `
 -InputObject $Tuple `
 -MemberType NoteProperty `
 -Name $Reader.GetName($i) `
 -Value $Reader.GetValue($i).ToString()
 }
 $Result+=$Tuple
 }
 $result | Format-Table 
 }
catch
{
 $ex = $_.Exceptio
 Write-Error "whilst reading the data from the datatable. $ex.Message"
}
$Reader.Close()
$Connection.Close()