代码之家  ›  专栏  ›  技术社区  ›  Shuvayan Das

使用字典将参数传递给python中的postgresql语句

  •  0
  • Shuvayan Das  · 技术社区  · 6 年前

    我定义了一个字典,其中包含几个参数及其值,这些参数及其值最终将用于构建SQL查询。

    query_params = collections.OrderedDict(
            {'table_name':'publilc.churn_data',
             'date_from':'201712',
             'date_to':'201805',
             'class_target':'NPA'
          })
    

    以下查询中将使用这些参数:

    sql_data_sample = str("""select * from %s # get value of table_name
                                        where dt = %s    #get value of date_from
                                        and target in ('ACTIVE')
    
                            ----------------------------------------------------
                            union all
                            ----------------------------------------------------
                            (select * from %s #get value of table_name
                                     where dt = %s #get value of date_to
                                     and target in (%s));""") #get value of class_target
                                        %("'"+.join(str(list(query_params.values())[0])) + "'" + 
                                        "'"+.join(list(query_params.values())[1]) + "'" + 
                                        "'"+.join(list(query_params.values())[2]) + "'" +
                                        "'"+.join(list(query_params.values())[3]) + "'" )
    

    但是,这给了我一个缩进误差,如下所示:

    get_ipython().run_line_magic('("\'"+.join(list(query_params.values())[0])', '+ "\'"')
        ^
    IndentationError: unexpected indent
    

    查询最终应如下所示:

    select *from public.churn_data
            where dt = '201712'
            and target in ('ACTIVE')
    
    ----------------------------------------------------
    union all
    ----------------------------------------------------
     (select * from public.churn_data 
                where dt = '201805'
                and target in ('NPA'));
    

    我不知道错误的根源在哪里,是不是因为公众。在表名中? 有人能帮我吗??

    2 回复  |  直到 6 年前
        1
  •  1
  •   shmee    6 年前

    请使用参数化查询,如中所述 the docs

    既然你已经听写了,你可以做:

    sql_data_sample = """select * from %(table_name)s
               where dt = %(date_from)s
               and target in ('ACTIVE')
               ----------------------------------------------------
               union all
               ----------------------------------------------------
               (select * from %(table_name)s
               where dt = %(date_to)s
               and target in (%(class_target)s));"""
    
    cur.execute(sql_data_sample, query_params)
    

    我还没有测试过它是否适用于一个命令式听写,但我认为它应该适用。如果没有,可以在将排序的dict作为参数映射传递之前使其成为常规dict。

    编辑 除非您以后需要将参数作为ordereddict,否则请使用常规dict。据我所见,您只选择ordereddict来保留 list(query_params.values())[0] .

    编辑2 不能使用绑定传递表名和字段名。安托万·杜斯(Antoine Dus_)Aux在 this answer 从2.7版开始,psycopg2提供了一种或多或少安全的方法。

    from psycopg2 import sql
    
    sql_data_sample = """select * from {0}
               where dt = %(date_from)s
               and target in ('ACTIVE')
               ----------------------------------------------------
               union all
               ----------------------------------------------------
               (select * from {0}
               where dt = %(date_to)s
               and target in (%(class_target)s));"""
    
    cur.execute(sql.SQL(sql_data_sample)
                    .format(sql.Identifier(query_params['table_name'])), 
                query_params)
    

    您可能需要删除 table_name 从您的dict中,我不确定psycopg2对参数dict中的其他项的反应如何,我现在无法测试它。

    应该指出的是,这仍然会带来SQL注入的风险,除非绝对必要,否则应该避免。通常,表名和字段名是查询字符串中相当固定的部分。

    这是相关的 documentation for the sql module .

        2
  •  -2
  •   nandudeore23    6 年前

    可以使用以下代码删除缩进错误

    sql_data_sample = str("""
    select * from %s
    where dt = %s
    and target in ('ACTIVE')
    ----------------------------------------------------
    union all
    ----------------------------------------------------
    (select * from %s
    where dt = %s
    and target in (%s));""" %(
        "'" + str(list(query_params.values())[0]) + "'" +
        "'" + list(query_params.values())[1] + "'" +
        "'" + list(query_params.values())[2] + "'" +
        "'" + list(query_params.values())[3] + "'"
    ))
    

    但您需要再传递一个参数,因为您使用了%s 5次,但参数只有4个