Question

I have [MySp], A stored procedure.

So check this out.. when I run this it works:

 SELECT ID,Name FROM Table

But, When I do this, I get an error on the application side (Adodb)

 Declare @Table TABLE(ID int,Name varchar(10))

 --- Inserts into table variable ---
 INSERT INTO @Table
 SELECT ID,Name FROM Table

 --- Returns data from table variable ---
 SELECT ID,Name FROM @Table

Keep in mind, in SQL Console i get the same results for [MySp], but in the application/adodb code i get errors.

ASP Code:

Set oRS = Server.CreateObject("Adodb.Recordset")
oRS.Open "[MySp]", Conn
If oRS.EOF Then...  <--Gives an error

 ADODB.Recordset error '800a0e78'
 Operation is not allowed when the object is closed. 

Does anyone know why I'm getting this error when I use Table variables in SQL?

Was it helpful?

Solution

Try adding SET NOCOUNT ON at the top of the stored procedure.

I have a vague recollection that ADO used to get confused by the result counts coming back from inserts/updates/deletes.

E.g.:

CREATE PROCEDURE MySP
AS

SET NOCOUNT ON

Declare @Table TABLE(ID int,Name varchar(10))

 --- Inserts into table variable ---
 INSERT INTO @Table
 SELECT ID,Name FROM Table

 --- Returns data from table variable ---
 SELECT ID,Name FROM @Table

OTHER TIPS

I had a slightly more complicated (but similar) issue NOT involving a stored proc.

Thought I would share in case anyone found themselves in a similar position.

PROBLEM

SQL:

DECLARE @a (
Alpha VARCHAR(10),
Beta INT
);
INSERT @a VALUES
('A', 1)

DECLARE @b (
Gamma DATE,
Delta INT
);
INSERT @b VALUES
('2014-01-01', 1)

SELECT *
FROM @a a
JOIN @b b ON a.Beta = b.Delta

VBA:

Sub GetData()
    Dim sSql
    Dim oConnection As New ADODB.Connection
    Dim oRecordSet As New ADODB.Recordset

    Call oRecordSet.Open(sSqlQuery, oConnection, adOpenStatic, adLockReadOnly)
    Call oConnection.Open("Provider=SQLOLEDB.1;Server=MyServer;Database=MyDB;Trusted_Connection=Yes;")

    sSql = <as Above>

    Call oRecordSet.Open(sSql, oConnection, adOpenStatic, adLockReadOnly)

    If oRecordSet.RecordCount > 0 Then
        ' DO STUFF WITH DATA
    End If

    ' Close objects
    oConnection.Close
    oRecordSet.Close
End Sub

SOLUTION

SQL_1

CREATE TABLE #a (
Alpha VARCHAR(10),
Beta INT
);
INSERT #a VALUES
('A', 1)

SQL_2

CREATE TABLE #b (
Gamma DATE,
Delta INT
);
INSERT #b VALUES
('2014-01-01', 1)

SQL_3

SELECT *
FROM #a a
JOIN #b b ON a.Beta = b.Delta

SQL_4

DROP TABLE #a;

SQL_5

DROP TABLE #b;

VBA

Sub GetData()
    Dim sSql
    Dim oConnection As New ADODB.Connection
    Dim oRecordSet As New ADODB.Recordset

    Call oConnection.Open("Provider=SQLOLEDB.1;Server=MyServer;Database=MyDB;Trusted_Connection=Yes;")

    sSql = <SQL_1>
    Call oConnection.Execute(sSql)

    sSql = <SQL_2>
    Call oConnection.Execute(sSql)

    sSql = <SQL_3>
    Call oRecordSet.Open(sSql, oConnection, adOpenStatic, adLockReadOnly)
    If oRecordSet.RecordCount > 0 Then
        ' DO STUFF WITH DATA
    End If

    sSql = <SQL_4>
    Call oConnection.Execute(sSql)

    sSql = <SQL_5>
    Call oConnection.Execute(sSql)

    oConnection.Close
    oRecordSet.Close
End Sub

Explanation

Basically my understanding is that VBA tries to get the results back after the initial INSERT, so separating it into the individual commands (Executes) and only opening the recordset when we are querying the data we want seems to do the trick.

A side issue of this is that I needed to use temporary tables (which I didn't actually realise I had permissions to do, as it is a live DB and I had never used these before) as I believe variable tables would have vanished by the time I made the second call.

Other things to be aware of

  • Ensure you only close the connection after you have done everything (initially I had each command called from separate functions and was opening/closing the connection each time without thinking about it)
  • Make sure you delete the temporary tables at the end

Hope this helps someone else!

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top