Home > Software engineering >  SQL param in python script in SQL proc
SQL param in python script in SQL proc

Time:01-06

I'm trying to use dynamic SQL passed to Python for execution, but cannot get the correct quote combination working for @key. Here is the proc:

    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 provides two errors, the first which I think may not apply is: 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)

The second Python error is: ('42000', "[42000] [Microsoft][ODBC Driver 17 for SQL Server][SQL Server]Incorrect syntax near the keyword 'key'. (156) (SQLExecDirectW)")

Triple single quotes does not work, nor does single double single.

(Yes I am passing SQL from SQL Server to Python, to then connect to SQL server and execute the SQL. The to_html() method is worth the effort).

CodePudding user response:

You are going to have a major SQL injection issue if you attempt what you are doing now.

The best solution here would be to pass back the HTML as an OUTPUT parameter:

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);

Your other option is to use parameters to do the insertion from the Python side. I feel this is less clean though, as scalar values can be returned through parameters as above, and dataframes can be returned through @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;
  •  Tags:  
  • Related