【问题标题】:Execute multiple variable query in SQL Server using Python cursor使用 Python 游标在 SQL Server 中执行多变量查询
【发布时间】:2021-11-20 12:27:51
【问题描述】:

我正在尝试使用 pymssql 库在 SQL Server 中执行多个查询。

这是我的代码:

cur = conn.cursor()
cur.execute("DECLARE @begin_time datetime, @end_time datetime, @from_lsn binary(10), @to_lsn binary(10);  
             SET @begin_time = DATEADD(day, -1, GETDATE()) ;  
             SET @end_time = GETDATE(); 
             SET @from_lsn = sys.fn_cdc_map_time_to_lsn('smallest greater than or equal', @begin_time);  
             SET @to_lsn = sys.fn_cdc_map_time_to_lsn('largest less than or equal', @end_time);
             SELECT * FROM cdc.fn_cdc_get_net_changes_dbo_users(@from_lsn, @to_lsn, 'all');")
output = cur.fetchall()
print(output)
conn.close()

代码运行良好并获取结果,但是当我使用 Python 库计算日期并将其传递给代码时,出现错误。

示例代码

from datetime import datetime, timedelta
end_date = datetime.now()
start_date = datetime.now() + timedelta(hours=-1)

cur = conn.cursor()
query =  f"""DECLARE @begin_time datetime, @end_time datetime, @from_lsn binary(10), @to_lsn binary(10);  
                SET @begin_time = {start_date};  
                SET @end_time = {end_date}; 
                SET @from_lsn = sys.fn_cdc_map_time_to_lsn('smallest greater than or equal', @begin_time);  
                SET @to_lsn = sys.fn_cdc_map_time_to_lsn('largest less than or equal', @end_time); 
                SELECT * FROM cdc.fn_cdc_get_all_changes_dbo_users (@from_lsn, @to_lsn, 'all');"""
print(query)
cur.execute(query)
output = cur.fetchall()
print(output)
conn.close()

错误:

ProgrammingError:(102,'11' 附近的语法不正确。

DB-Lib 错误消息 20018,严重性 15:
常规 SQL Server 错误:检查来自 SQL Server 的消息

我不确定我在这里做错了什么。如果有人可以帮助我并解释问题,我将不胜感激。

【问题讨论】:

  • 错误信息显示其语法不正确
  • 这就是我无法弄清楚我在哪里得到错误语法的原因,因为当我使用 sql 查询计算时间时,相同的查询工作正常。
  • 这可能是因为 dateformat 被传递给 sql server 块的方式。你能以 YYYY-MM-DD hh24:mi:ss 格式传递 start_time
  • 我试过了,但没用 :(
  • 当您打印查询时,您的日期值是否包含在' 字符中?您可以尝试使用Binding Parameters 来确保它们得到正确处理。

标签: python sql-server pymssql


【解决方案1】:

考虑时间变量的实际 SQL 参数化,而不是字符串插值或与 F 字符串的连接,这对于将值从应用层传递到后端数据库通常不安全或不高效。库pymssql 支持parameters。 Python 的 datetime.datetime 应该转换为 MSSQL 的 DATETIME

# PREPARED STATEMENTS WITH %s PLACEHOLDERS
query = """DECLARE @begin_time datetime, @end_time datetime, @from_lsn binary(10), @to_lsn binary(10);  
           SET @begin_time = %s;  
           SET @end_time = %s; 
           SET @from_lsn = sys.fn_cdc_map_time_to_lsn('smallest greater than or equal', @begin_time);  
           SET @to_lsn = sys.fn_cdc_map_time_to_lsn('largest less than or equal', @end_time); 
           SELECT * FROM cdc.fn_cdc_get_all_changes_dbo_users (@from_lsn, @to_lsn, 'all');
        """
print(query)

# EXECUTE QUERY WITH BINDED PARAMS
cur.execute(query, [start_date, end_date])

其实你可以缩短查询,因为参数不需要声明:

# PREPARED STATEMENTS WITH %s PLACEHOLDERS
query = """DECLARE @from_lsn binary(10), @to_lsn binary(10);
           SET @from_lsn = sys.fn_cdc_map_time_to_lsn('smallest greater than or equal', %s);  
           SET @to_lsn = sys.fn_cdc_map_time_to_lsn('largest less than or equal', %s); 
           SELECT * FROM cdc.fn_cdc_get_all_changes_dbo_users (@from_lsn, @to_lsn, 'all');
        """

顺便说一下,请注意pymmsql 不再是一个维护的库。考虑pyodbc 以获得最安全、更新的用于 Python-SQL Server 连接的 DB-API。但请注意,pyodbc 的参数占位符是 qmarks ? 而不是 %s(与大多数 Python DB-API 不同)。

【讨论】:

  • 很高兴为您提供帮助!编码愉快!
猜你喜欢
  • 2021-10-27
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-01-20
  • 1970-01-01
  • 1970-01-01
  • 2011-05-14
  • 1970-01-01
相关资源
最近更新 更多