【问题标题】:Create a dynamic sql query by removing a value from string type通过从字符串类型中删除值来创建动态 sql 查询
【发布时间】:2022-01-31 03:13:40
【问题描述】:

我有一个 python GUI 框架,它允许使用下拉列表并从下拉列表和窗口中的任何表单提交框中返回键/值列表。我要解决的问题是我需要传递从字符串类型中删除的这些值之一,特别是下拉列表中的“名字”值,因为它作为'FirstName' 而不是FirstName 传递给MySQL 语句.

我试图通过使用PREPARE 语句在 MySQL 端解决这个问题,但它似乎不是一个解决方案。

SQL_queries 文件

upi_update = '''UPDATE supplements_test.people
                SET %(selection)s = %(first)s
                WHERE IndividualID = CAST(%(id)s AS UNSIGNED)'''

usi_update = '''UPDATE supplements_test.supplements
                SET %(selection)s = %(SuppName)s
                WHERE SuppID = CAST(%(id)s AS UNSIGNED)'''

主程序文件

import mysql.connector as mysql
# local file holding several dynamic query sets with validations/updates/inserts
# small sample above
import SQL_queries as sq


# MySQL connection code
cnx = mysql.connect(connection_info_here)
cur = cnx.cursor()

# key generated based on what functionality the user chooses from menu.
q_key = 'upi'

# Key value pairs returned from the GUI drop down selection/form input fields. 
keys = {'first': 'John',
        'last': 'Smith',
        'email': 'j.smith@gmail.com',
        'id': '1',
        'selection': 'FirstName'}



cur.execute(eval(f'sq.{q_key}_update'), params=keys)
conn.commit()

更新

在意识到我对问题的复杂性描述不佳后,通过给出一个试图简化我的代码的代码示例,我用更多信息编辑了原件,并找到了一个作为自我答案发布的解决方案。

【问题讨论】:

    标签: python mysql


    【解决方案1】:

    SQL 查询参数不适用于列名等标识符。每个查询参数在查询中都表现为字符串值,因此在您的示例中,它的执行就像您编写了以下查询一样:

    UPDATE supplements_test.people
    SET 'FirstName' = 'John'
    WHERE IndividualID = CAST('1' AS UNSIGNED)
    

    这不是合法的 UPDATE 语句,因为你不能使用文字值作为赋值的左侧(这在大多数编程语言中是相似的,即分配 4 = 12 没有意义)。

    因此您不能将查询参数用于标识符。所有查询语法和标识符必须在查询字符串中固定,然后将其传递给 MySQL 进行解析。只有查询的元素才能作为参数。

    此外,我很确定将参数传递给 cur.execute() 要求您在字典中没有额外的键,除了将用于参数的键。


    关于您的评论:这是一个使用 Python 的 f 字符串将 Python 变量插入字符串的示例。

    # Key value pairs returned from the GUI. 
    keys = {'first': 'John',
            'last': 'Smith',
            'email': 'j.smith@gmail.com',
            'id': '1',
            'selection': 'FirstName'}
    
    stmt = f'''UPDATE supplements_test.people
              SET `{keys['selection']}` = %(first)s
              WHERE IndividualID = CAST(%(id)s AS UNSIGNED)'''
    

    我将表达式放在查询中的反引号内,因为在 MySQL 中,反引号会保护标识符,以防它是保留的 SQL 关键字或包含空格或某些特殊字符。 f-string 表达式本身就是{keys['selection']}

    f-string 使用字符串替换将变量插入到查询本身中。

    F 字符串不关心 %s 占位符。这些通过不变。我可以在 python 交互式 shell 中显示结果值:

    >>> stmt
    'UPDATE supplements_test.people\n              SET `FirstName` = %(first)s\n              WHERE IndividualID = CAST(%(id)s AS UNSIGNED)'
    

    现在可以将此字符串用作查询,并传递一个只包含所需参数的字典:

    p = {'first': keys['first'], 'id': keys['id']}
    cur.execute(stmt, p)
    

    【讨论】:

    • 正确。我需要找到一个解决方案,将字符串转换为字段标识符的形式。听起来它必须在 python 端完成。
    • 感谢您的知识,并为浪费您的时间和精力而道歉。我的原始帖子解释得很差,试图在示例中保存一堆代码。我已经修改了代码并发布了一个我偶然发现的解决方案。
    【解决方案2】:

    注意:这不是一个很好的解决方案,并且存在注入攻击风险,但它确实有效。需要找到另一种防止恶意输入的方法。

    将此答案形成为源自How to postpone/defer the evaluation of f-strings?

    SQL_queries 文件

    upi_update = '''UPDATE supplements_test.people
                    SET {keys["selection"]} = %(first)s
                    WHERE IndividualID = CAST(%(id)s AS UNSIGNED)'''
    
    usi_update = '''UPDATE supplements_test.supplements
                    SET %(selection)s = %(SuppName)s
                    WHERE SuppID = CAST(%(id)s AS UNSIGNED)'''
    

    删除了从 execute 方法中读取的动态 sql 的 eval 语句到变量中,以将其放入与 keys 变量相同的文件中。 对嵌套在 fstring 中的 fstring 进行 Eval,以从呈现为字符串的过程中移除 FirstName,并传递其他保留字符串。

    主程序文件

    import mysql.connector as mysql
    # local file holding several dynamic query sets with validations/updates/inserts
    # small sample above
    import SQL_queries as sq
    
    
    # MySQL connection code
    cnx = mysql.connect(connection_info_here)
    cur = cnx.cursor()
    
    # key generated based on what functionality the user chooses from menu.
    q_key = 'upi'
    
    # Key value pairs returned from the GUI drop down selection/form input fields. 
    keys = {'first': 'John',
            'last': 'Smith',
            'email': 'j.smith@gmail.com',
            'id': '1',
            'selection': 'FirstName'}
    
    
    
    query = eval(f'sq.{q_key}_update')
    cur.execute(eval(f"f'{query}'"), params=keys)
    conn.commit()
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-03-10
      • 2012-05-21
      • 1970-01-01
      • 1970-01-01
      • 2015-11-28
      相关资源
      最近更新 更多