question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

Stored Procedure executemany does not return selected value

See original GitHub issue
  • Python: 3.10.2 64bit
  • pyodbc: 4.0.32
  • OS: Windows 10 64bit
  • DB: SQL Server (MSSQL)
  • driver: ‘ODBC Driver 17 for SQL Server’

I have the following stored procedure. I create some variables in the beginning that I select no matter what happens in the end as they indicate information about the success of the procedure. So I want to insert, then have the select return a row in the end. I also call this single stored procedure with executemany on multiple objects. Running the stored procedure in SQL Server Management Studio is working fine and gives back the desired select in the end no matter what. Calling the same from pyodbc only returns the select if I run execute or executemany on exactly 1 object.

Ideally I would like to receive a response for all objects I give to executemany with fast_executemany set to True. If I set fast_executemany to True I get nothing back, just ‘Previous SQL was not a query’.

I have SET NOCOUNT ON in the procedure and I have also set autocommit on when creating the connection. No matter what I do, .fetchall() gives back 'pyodbc.ProgrammingError: No results. Previous SQL was not a query.' The row gets inserted correctly and everything works fine, but I am not getting back the return value in Python. Removing fastexecute_many = True will make the function give back exactly only 1 row of result, but the rest are left out. If I call the executemany function on many rows I would expect to get back a result for each insert. This leaves me with using just execute on rows one-by-one which is not ideal as I am working with many thousands of rows.

How can I use executemany with fast_executemany set to True on multiple objects with all of them getting a return value in the end in an array?

CREATE PROCEDURE [Letters].[spInsertSecretary]
(
    @role NVARCHAR(50),
    @name NVARCHAR(255),
    @source NVARCHAR(20),
    @company_id NVARCHAR(10),
    @country NVARCHAR(55) = NULL,
    @region NVARCHAR(100) = NULL,
    @postal_code NVARCHAR(20) = NULL,
    @locality NVARCHAR(100) = NULL,
    @premises NVARCHAR(100) = NULL,
    @address_line_1 NVARCHAR(255) = NULL,
    @address_line_2 NVARCHAR(255) = NULL,
    @country_of_residence NVARCHAR(55) = NULL,
    @appointed_on DATETIME2 = NULL,
    @occupation NVARCHAR(55) = NULL,
    @nationality NVARCHAR(55) = NULL,
    @date_of_birth DATETIME2 = NULL,
    @resigned_on DATETIME2 = NULL,
    @name_normal NVARCHAR(255) = NULL
)
AS
BEGIN
    SET NOCOUNT ON;
    DECLARE @HasError BIT = 0
    DECLARE @InsertedId INT = NULL
    DECLARE @ErrorLine INT = NULL
    DECLARE @ErrorMessage NVARCHAR(1000) = NULL

    BEGIN TRY
        INSERT INTO [Letters].[Secretary]
        (
            role,
            name,
            source,
            company_id,
            country,
            region,
            postal_code,
            locality,
            premises,
            address_line_1,
            address_line_2,
            country_of_residence,
            appointed_on,
            occupation,
            nationality,
            date_of_birth,
            resigned_on,
            name_normal,
            created_at,
            last_updated_at
        )
        VALUES
        (
            @role,
            @name,
            @source,
            @company_id,
            @country,
            @region,
            @postal_code,
            @locality,
            @premises,
            @address_line_1,
            @address_line_2,
            @country_of_residence,
            @appointed_on,
            @occupation,
            @nationality,
            @date_of_birth,
            @resigned_on,
            @name_normal,
            GETDATE(),
            GETDATE()
        )

        SET @InsertedId = SCOPE_IDENTITY()

    END TRY
    BEGIN CATCH

        SET @HasError = 1
        SET @ErrorLine = ERROR_LINE()
        SET @ErrorMessage = ERROR_MESSAGE()

    END CATCH

    SELECT 
        @InsertedId AS 'InsertedId',
        @HasError AS 'HasError',
        @ErrorMessage AS 'ErrorMessage',
        @ErrorLine AS 'ErrorLine'

END
GO
connection_string = f"DRIVER={{ODBC Driver 17 for SQL Server}};SERVER={Config.DATABASE_SERVER_NAME};DATABASE={Config.DATABASE_NAME};UID={Config.DATABASE_USERNAME};PWD={Config.DATABASE_PASSWORD};trusted_connection=yes;autocommit=yes;"
query = 'EXEC Letters.spInsertSecretary @role=?, @name=?, @company_id=?, @country_of_residence=?, @appointed_on=?, @occupation=?, @nationality=?, @date_of_birth=?, @resigned_on=?, @name_normal=?, @source=?, @country=?, @region=?, @postal_code=?, @locality=?, @premises=?, @address_line_1=?, @address_line_2=?'
param_values = (('secretary', 'MARTIN, Rosemary Elisabeth Scudamore', '01833679', None, datetime.datetime(2010, 3, 30, 0, 0), None, None, None, None, None, 'COMPANIES HOUSE', None, 'Berkshire', 'RG14 2FN', 'Newbury', None, 'Vodafone House', 'The Connection'),('secretary', 'MARTIN, Rosemary Elisabeth Scudamore', '01833679', None, datetime.datetime(2010, 3, 30, 0, 0), None, None, None, None, None, 'COMPANIES HOUSE', None, 'Berkshire', 'RG14 2FN', 'Newbury', None, 'Vodafone House', 'The Connection'))
with pyodbc.connect(connection_string) as connection:
    with connection.cursor() as cursor:
        cursor.fast_executemany = True
        result = cursor.executemany(query, param_values) # result becomes None
        return_value = cursor.fetchall() # pyodbc.ProgrammingError: No results.  Previous SQL was not a query.

As I have stated, the inserts happen, but I get no result back for any of them from the select at the end.

Issue Analytics

  • State:closed
  • Created a year ago
  • Comments:7 (2 by maintainers)

github_iconTop GitHub Comments

1reaction
gordthompsoncommented, Jul 26, 2022

.executemany() is not specifically designed to return result sets. PEP 249 says:

Use of this method for an operation which produces one or more result sets constitutes undefined behavior, and the implementation is permitted (but not required) to raise an exception when it detects that a result set has been created by an invocation of the operation.

So if you want result set(s) you need to use .execute(). You can either

  • employ the OPENJSON trick,
  • use a loop as suggected by @v-chojas , or
  • you can modify your stored procedure to accept a table-valued parameter (TVP) and then use that in your .execute() call.
0reactions
CaptainCsabacommented, Jul 26, 2022

Thank you very much. I got my answers. The thread can be closed

Read more comments on GitHub >

github_iconTop Results From Across the Web

Can I use pyodbc executemany with sql stored procedure?
Yes, we can use executemany with Stored Procedures in SQL Server: ... SET NOCOUNT ON; INSERT INTO Table_1 (id, name, salary) VALUES (@id, ......
Read more >
fast_execute many stops after x inserts #1053 - GitHub
I am calling this on the python side with the fast_executemany parameter set to True. Inserting around 1500 rows never goes though, ...
Read more >
Python ODBC Example -- Stored Procedures - Easysoft
# Python. · # We place the alphabet in a list of values and select records ; # is also returned to indicate...
Read more >
Microsoft SQL Server - SQLAlchemy 1.4 Documentation
INSERT INTO t (x) OUTPUT inserted.id VALUES (?) When RETURNING is not available or has been disabled via ...
Read more >
CRUD Operations in SQL Server using Python
In practice, a stored procedure may have output parameters and return values. As of this writing, pyodbc does not implement a method that ......
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found