【问题标题】:SQL param in python script in SQL procSQL proc中python脚本中的SQL参数
【发布时间】:2022-01-05 06:37:42
【问题描述】:

我正在尝试使用传递给 Python 的动态 SQL 来执行,但无法为 @key 获得正确的引号组合。这是过程:

    create procedure [dbo].[pr_select_to_html_table]
    (
        @key        varchar(100),
        @sql_query  nvarchar(max) = null
    )
    AS

    DECLARE @NewScript NVARCHAR(MAX) 
    SET @NewScript  = N'
    import pandas as pd
    import pyodbc

    def exec_sql (query) :
        # execute sql query with no return
        cnxn_p = pyodbc.connect("driver={odbc driver 17 for sql server};server=localhost;DATABASE=trader;trusted_connection=yes;")
        cursor_p = cnxn_p.cursor()
        try:
            cursor_p.execute(query)
        except pyodbc.Error as err:
                print(err)
        cnxn_p.commit()

    #Read Data From Input @input_data_1 
    df = my_input_data
    df.index = df.index+1

    result = df.to_html()
    sql = "insert into wrk.html_table (key,html_result) values (''' + @key + ''' ,''" + result + "'')"
    exec_sql(sql)
        '

        EXEC sp_execute_external_script
          @language = N'Python'
        , @Script = @NewScript
        , @input_data_1 = @sql_query
        , @input_data_1_name = N'my_input_data'

Python 提供了两个错误,我认为第一个错误可能不适用: UserWarning: Pandas doesn't allow columns to be created via a new attribute name - see https://pandas.pydata.org/pandas-docs/stable/indexing.html#attribute-access setattr(result, "var_info", var_info)

第二个 Python 错误是:('42000', "[42000] [Microsoft][ODBC Driver 17 for SQL Server][SQL Server]关键字'key'附近的语法不正确。(156) (SQLExecDirectW)")

三单引号不行,单双单引号也不行。

(是的,我将 SQL 从 SQL Server 传递到 Python,然后连接到 SQL Server 并执行 SQL。to_html() 方法值得努力)。

【问题讨论】:

    标签: sql python-3.x sql-server-2019


    【解决方案1】:

    如果你尝试你现在正在做的事情,你将会遇到一个重大的 SQL 注入问题。

    这里最好的解决方案是将 HTML 作为 OUTPUT 参数传回:

    create procedure [dbo].[pr_select_to_html_table]
    (
        @key        varchar(100),
        @sql_query  nvarchar(max) = null
    )
    AS
    
    DECLARE @NewScript NVARCHAR(MAX) 
    SET @NewScript  = N'
    import pandas as pd
    
    #Read Data From Input @input_data_1 
    df = my_input_data
    df.index = df.index+1
    
    html = df.to_html()
         '
    
    DECLARE @html nvarchar(max);
    
    EXEC sp_execute_external_script
           @language = N'Python'
         , @Script = @NewScript
         , @input_data_1 = @sql_query
         , @input_data_1_name = N'my_input_data'
         , @params = N'@html nvarchar(max) OUTPUT'
         , @html = @html OUTPUT;
    
    insert into wrk.html_table (key, html_result)
    values (@key, @html);
    

    您的另一个选择是使用参数从 Python 端进行插入。我觉得这不太干净,因为标量值可以通过上述参数返回,而数据帧可以通过@output_data_1_name返回

    create procedure [dbo].[pr_select_to_html_table]
    (
        @key        varchar(100),
        @sql_query  nvarchar(max) = null
    )
    AS
    
    DECLARE @NewScript NVARCHAR(MAX) 
    SET @NewScript  = N'
    import pandas as pd
    import pyodbc
    
    #Read Data From Input @input_data_1 
    df = my_input_data
    df.index = df.index+1
    
    result = df.to_html()
    sql = """
    insert into wrk.html_table (key, html_result)
    values (?, ?)"""
    
    # execute sql query with no return
    cnxn_p = pyodbc.connect("driver={odbc driver 17 for sql server};server=localhost;DATABASE=trader;trusted_connection=yes;")
    cursor_p = cnxn_p.cursor()
    try:
        cursor_p.execute(query, key, result)
    except pyodbc.Error as err:
            print(err)
    cnxn_p.commit()
    
    exec_sql(sql)
         '
    
    EXEC sp_execute_external_script
           @language = N'Python'
         , @Script = @NewScript
         , @input_data_1 = @sql_query
         , @input_data_1_name = N'my_input_data'
         , @params = N'@key varchar(100)'
         , @key = @key;
    

    【讨论】:

    • 不使用动态 SQL 就干净多了。 (需要删除多余的逗号,以及 Python 脚本中的前导空格,以避免出现“IndentationError: unexpected indent”)
    • 继续edit:我的 Python 不是很好,所以我可能有一些错误
    猜你喜欢
    • 1970-01-01
    • 2011-12-21
    • 2022-12-22
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-02-27
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多