Excel VBA - SQL调用 - 关闭对象时不允许操作

时间:2016-03-04 19:52:43

标签: sql-server excel-vba ssms-2014 vba excel

我有几个宏来调用SSMS 2014来运行查询并在我的工作表中的已定义单元格中返回结果。它们成功运行,但是当我尝试对临时表使用某些查询时,我收到以下错误消息:

VBA Error Message

我在线研究过,我能找到的最佳答案是在查询开头添加SET NOCOUNT ON。我试过了,仍然得到了同样的信息。

Debug带给我的一段代码如下:

bqr.Range("B6").CopyFromRecordset rst

我的代码中的肉和土豆以及重要的变量设置如下:

Dim cnn As New ADODB.Connection
Dim rst As New ADODB.Recordset
Dim ConnectionString As String
Dim StrQuery As String
Dim SOURCE As String
Dim DATABASE As String
Dim QUERY As String
Dim intColIndex As Integer
Dim sDate As String
Dim eDate As String
Dim qt As Worksheet
Dim qtr As Worksheet
Dim bqr As Worksheet
Dim bp As Worksheet

ConnectionString = "Provider=SQLOLEDB;Data Source=" & SOURCE & "; Initial Catalog=" & DATABASE & "; Integrated Security=SSPI;"
cnn.Open ConnectionString

cnn.CommandTimeout = 900

StrQuery = QUERY

rst.Open StrQuery, cnn

bqr.Range("B6").CopyFromRecordset rst

For intColIndex = 0 To rst.Fields.Count - 1
    Range("B5").Offset(0, intColIndex).Value = rst.Fields(intColIndex).Name
Next

最令人困惑的部分是该错误表明我的rst记录集已关闭,即使它在我使用CopyFromRecordset

之前打开

我尝试在查询结束时添加DROP TABLE,在开头添加SET NOCOUNT ON函数,甚至测试一些较小的简单临时表作为测试。

例如,我将QUERY变量设置为:

QUERY = "CREATE TABLE #Test1 (TestID INT, TestValue VARCHAR(20))"
QUERY = QUERY + " INSERT INTO #Test1"
QUERY = QUERY + " VALUES (1, 'Pass'), (2, 'Fail'), (3, 'Try Again')"
QUERY = QUERY + " SELECT * INTO #Test2 FROM #Test1 WHERE TestID = 1"
QUERY = QUERY + " SELECT * FROM #Test2"

然后运行代码以提取并过去到Excel中,它起作用了。

因此,我很难过。也许查询可以有多长时间?现在它长180线,所以它很大......

任何建议都表示赞赏!

编辑:下面的完整宏(减去实际查询):

Private Sub CommandButton1_Click()

If TextBox1.Value = "i.e. 20160101" Or TextBox2.Value = "i.e. 20160131" Then

MsgBox "Please fill out all fields before proceeding"

ElseIf Len(TextBox1.Value) <> 8 Or Len(TextBox2.Value) <> 8 Or Not IsNumeric(TextBox1.Value) Or Not IsNumeric(TextBox2.Value) Then

MsgBox "Please use correctly formatted Datekeys (i.e. yyyymmdd)"

Else

Application.DisplayAlerts = False

Sheets(ActiveWorkbook.Sheets.Count).Select

While ActiveSheet.Name <> "[worksheet I want to keep]"

ActiveSheet.Delete

Sheets(ActiveWorkbook.Sheets.Count).Select

Wend

Dim cnn As New ADODB.Connection
Dim rst As New ADODB.Recordset
Dim ConnectionString As String
Dim StrQuery As String
Dim SOURCE As String
Dim DATABASE As String
Dim QUERY As String
Dim intColIndex As Integer
Dim sDate As String
Dim eDate As String
Dim qtr As Worksheet
Dim bqr As Worksheet
Dim bp As Worksheet

Set qtr = Sheets([sheet name])

Sheets.Add after:=qtr
Set bqr = ActiveSheet
bqr.Name = "[sheet name]"
Sheets.Add after:=bqr
Set bp = ActiveSheet
bp.Name = "[sheet name]"

SOURCE = "[server]"
DATABASE = "[database]"
sDate = UserForm1.TextBox1.Value
eDate = UserForm1.TextBox2.Value

QUERY = "[beginning of query]"
QUERY = QUERY + " [more query here]" 'This gets repeated a lot for each additional line in the query'

qtr.Select
Range("B6").Select

While ActiveCell.Value <> ""

QUERY = QUERY + " " + ActiveCell.Value

ActiveCell.Offset(1, 0).Select

Wend

QUERY = QUERY + " [more query here]" 'This gets repeated a lot for the remaining lines in the query'



    ConnectionString = "Provider=SQLOLEDB;Data Source=" & SOURCE & "; Initial Catalog=" & DATABASE & "; Integrated Security=SSPI;"

    cnn.Open ConnectionString

    cnn.CommandTimeout = 2000


    StrQuery = QUERY


    rst.Open StrQuery, cnn

    bqr.Range("B6").CopyFromRecordset rst
For intColIndex = 0 To rst.Fields.Count - 1
    Range("B5").Offset(0, intColIndex).Value = rst.Fields(intColIndex).Name
Next

End If

Application.DisplayAlerts = True

End Sub

1 个答案:

答案 0 :(得分:0)

使用set nocount on;

启动您的T-SQL查询
QUERY = "set nocount on;"
QUERY = QUERY & "declare @Test1 table (TestID INT, TestValue VARCHAR(20))"
QUERY = QUERY & " INSERT INTO @Test1"
QUERY = QUERY & " VALUES (1, 'Pass'), (2, 'Fail'), (3, 'Try Again')"
QUERY = QUERY & " SELECT * FROM @Test1 WHERE TestID = 1"

然后它应该工作。下一个示例也将起作用,并且更接近您的示例(但使用表变量)。

set nocount on;
declare @Test1 table (TestID INT, TestValue VARCHAR(20))
declare @Test2 table (TestID INT, TestValue VARCHAR(20))

INSERT INTO @Test1
VALUES (1, 'Pass'), (2, 'Fail'), (3, 'Try Again')

insert into @Test2
select *
from @Test1 WHERE TestID = 1

select * from @Test2