【问题标题】:sql server return value with pyodbc带有pyodbc的sql server返回值
【发布时间】:2018-01-29 17:48:07
【问题描述】:

我正在尝试使用pyodbc 运行一些存储过程并使用以下代码获取单个返回值:

conn = pyodbc.connect("driver={SQL Server};server=MyServer;database=MyDB;trusted_connection=true") 

cursor = conn.cursor()

SQL_command = """
                DECLARE @ret INT

                EXEC @ret = [dbo].proc_mySP             
                  @group= 0
                , @description =?

                SELECT @ret
              """

cursor.execute(SQL_command, description)
retValue = cursor.fetchall()

存储过程的框架如下:

-- SOME CODE
-- ......
-- EXEC another_sp
-- DECLARE @RET INT
-- SELECT @RET as retValue
-- ......

上面的 sql 在 sql server 中运行良好,但是,当它被上面的 Python 代码调用时,它给出了错误消息:

pyodbc.ProgrammingError: ('24000', '[24000] [Microsoft][ODBC SQL 服务器驱动]游标状态无效 (0) (SQLNumResultCols)')

我可以知道我的代码有什么问题吗?

非常感谢。

【问题讨论】:

    标签: python sql return-value pyodbc


    【解决方案1】:

    尝试通过 pyodbc 运行多语句 T-SQL 脚本可能会出现问题。即使这在 SSMS 中运行良好

    DECLARE @tbl AS TABLE (retVal INT);
    INSERT INTO @tbl (retVal) 
            EXEC [dbo].proc_mySP
                    @group = 37,
                    @description = 'foo';
    SELECT retVal FROM @tbl;
    

    以下 Python 代码 ...

    sql = """\
    DECLARE @tbl AS TABLE (retVal INT);
    INSERT INTO @tbl (retVal) 
            EXEC [dbo].proc_mySP
                    @group = 37,
                    @description = ?;
    SELECT retVal FROM @tbl;
    """
    crsr.execute(sql, ['foo'])
    row = crsr.fetchone()
    

    ...失败了

    pyodbc.ProgrammingError:没有结果。以前的 SQL 不是查询。

    如果存储过程返回带有单列的单行结果集,那么您需要做的就是

    import pyodbc
    cnxn = pyodbc.connect("DSN=myDb_SQLEXPRESS")
    crsr = cnxn.cursor()
    sql = """\
    EXEC [dbo].proc_mySP
            @group = 37,
            @description = ?;
    """
    crsr.execute(sql, ['foo'])
    the_result = crsr.fetchone()[0]
    print(the_result)
    

    【讨论】:

      【解决方案2】:

      通过添加 SET NOCOUNT ON; 在我自己的代码中出现此错误;作为您从 Python 传递的 SQL 的第一行。

      conn = pyodbc.connect("driver={SQL Server};server=MyServer;database=MyDB;trusted_connection=true") 
      
      cursor = conn.cursor()
      
      SQL_command = """
                      SET NOCOUNT ON;
                      DECLARE @ret INT
      
                      EXEC @ret = [dbo].proc_mySP             
                        @group= 0
                      , @description =?
      
                      SELECT @ret
                    """
      
      cursor.execute(SQL_command, description)
      retValue = cursor.fetchall()
      

      【讨论】:

      • 不要认为这回答了问题。 SET NOCOUNT ON 抑制 N row(s) affected 消息,它不会影响存储过程结果集、返回码或输出参数。
      • 确实如此。我很清楚它在 SSMS 内部应该做什么以及做什么。但是,当从 Python 连接到 MSSQL 并运行多个 SQL 语句时,使用该代码使 Python 能够接受结果。您可能应该在声明它们不正确之前进行测试,因为我遇到过并以多种语言多次解决了这个问题。从 Python、R 和 VBA 运行多行 tsql 时,必须将 NOCOUNT 设置为 ON。否则,您将在这三个中的每一个中遇到不同的、无用的错误。
      • 相当不可思议的人在没有测试任何东西的情况下对我的答案投了反对票。 Gord 的上述回答很好,但我的要好得多,因为他只适用于获得一行,而我的适用于所有多行 tsql。很想在他们测试后收到反对票的回复。
      【解决方案3】:

      只需添加“SET NOCOUNT ON;”作为过程的第一行,pyodbc 将能够在过程结束时从 select 语句中获取数据。

      【讨论】:

      • 请提供有关您的解决方案的更多详细信息,而不是一句话。问题源代码中应包含SET NOCOUNT ON; 的位置?
      猜你喜欢
      • 2021-05-13
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多