如何使用 Python/SQLAlchemy 和 MSSQL 在一条 SQL 中执行多个插入/更新查询?

Guo*_*ang 5 python sql-server sqlalchemy exception pyodbc

我\xe2\x80\x99m是Python和SQLAlchemy的新手,我试图了解如何使用Python/SQLAlchemy在一个SQL中执行多个插入/更新查询:

\n\n

要求\n在一个 SQL 中执行多个插入/更新:

\n\n
DECLARE @age INT = 160\nINSERT INTO TEST_TABLE VALUES (\'QZ_TEST\', @age + 1)\nINSERT INTO TEST_TABLE VALUES (\'QZ_TEST\', \'not a number\')\nINSERT INTO ANOTHER_TABLE VALUES (\'QZ_TEST\', @age + 2)\n
Run Code Online (Sandbox Code Playgroud)\n\n

要知道这个查询看起来很难看,但我们确实有很多类似的查询。(我们使用的是已有 20 年左右历史的遗留数据库)

\n\n

Python代码

\n\n
def OdbcEngineSA(driver, conn_str):\n    def connect():\n        return pyodbc.connect(conn_str, autocommit=True, timeout=120)\n    return sqlalchemy.create_engine(driver + \'://\', creator=connect)\n\ndef get_db_connection():\n    return OdbcEngineSA(\'mssql\', \'DSN=mssql;Server=server,15001;database=DEV;UID=user_abc;PWD=pw_\')\n\ndef main():\n    db_connection = get_db_connection()\n    sql = """\n    DECLARE @age INT = 160\n    INSERT INTO TEST_TABLE VALUES (\'QZ_TEST\', @age + 1)\n    INSERT INTO TEST_TABLE VALUES (\'QZ_TEST\', \'not a number\')\n    INSERT INTO ANOTHER_TABLE VALUES (\'QZ_TEST\', @age + 2)\n    """\n    try:\n        db_connection.execute(sql)\n        db_connection.commit()\n        logger.info(\'db updated\')   \n    except Exception as e:\n        logger.error(\'Exception captured as expected: %s\', e)\n        db_connection.rollback()\n
Run Code Online (Sandbox Code Playgroud)\n\n

请注意

\n\n
INSERT INTO TEST_TABLE VALUES (\'QZ_TEST\', \'not a number\')\n
Run Code Online (Sandbox Code Playgroud)\n\n

如果我使用 SQL 客户端运行此单个查询,将触发错误: \n[S0001][245] 将 varchar 值“不是数字”转换为数据类型 int 时转换失败。

\n\n

我期待 Python 捕获异常,但是Python 代码运行时没有任何异常。即使我将 SQL 替换为

\n\n
BEGIN TRY\n        DECLARE @age INT = 160\n        INSERT INTO TEST_TABLE VALUES (\'QZ_TEST\', @age + 1)\n        INSERT INTO TEST_TABLE VALUES (\'QZ_TEST\', \'not a number\')\n        INSERT INTO ANOTHER_TABLE VALUES (\'QZ_TEST\', @age + 2)\nEND TRY\n    BEGIN CATCH\n        DECLARE @ErrorMessage NVARCHAR(4000)\n        DECLARE @ErrorSeverity INT\n        DECLARE @ErrorState INT\n\n        SELECT \n            @ErrorMessage = ERROR_MESSAGE(),\n            @ErrorSeverity = ERROR_SEVERITY(),\n            @ErrorState = ERROR_STATE()\n\n        RAISERROR (@ErrorMessage,\n                   @ErrorSeverity, -- Level 16\n                   @ErrorState\n                   )\n    END CATCH\n
Run Code Online (Sandbox Code Playgroud)\n\n

我的问题

\n\n
    \n
  • 我是否使用正确的方法来执行查询?
  • \n
  • 如果我的代码没问题,我如何从 Python 捕获实际的 SQL 异常?
  • \n
\n

Fli*_*rPA 0

execute命令可能在准备您的语句时出现问题,因为它实际上是多个语句。对于您想要做的事情,我相信您可能想看看executemany

https://github.com/mkleehammer/pyodbc/wiki/Cursor#executemanysql-paras

它采用不同的形式,并将 INSERT 值绑定为列表中的元组。

祝你好运!