【问题标题】:Generate SQL statements with python [duplicate]用python生成SQL语句[重复]
【发布时间】:2010-12-06 13:04:00
【问题描述】:

我需要从 html 文件生成插入语句列表(用于 postgresql),是否有可用于 python 的库来帮助我正确转义和引用名称/值?在 PHP 中我使用 PDO 进行转义和引用,是否有任何等效的 python 库?

编辑:我需要生成一个带有 sql 语句的文件,以便稍后执行

【问题讨论】:

  • 使用内联数据生成“普通 SQL 语句”本质上容易出现安全故障,原因很抽象,例如数据库引擎和生成的库之间对 Unicode 字符的不同解释。这不是你应该尝试做的事情。因此,输出应该被表述为 - 并传递给您的数据库 API - 作为查询字符串/数据列表组合。 SQLAlchemy 将自动执行此操作。
  • 我明白了,但是用例正在生成一个稍后执行的SQL文件

标签: python sql postgresql psycopg2


【解决方案1】:

我知道这是一个老问题,但我经常想要 OP 想要的东西:用于生成基本 SQL 的非常简单的库。

下面的函数就是这样做的。你给他们一个表名和一个包含你想要使用的数据的字典,然后他们返回你需要的操作的 SQL 查询。

键/值对代表数据库行中的字段名称和值。

def read(table, **kwargs):
    """ Generates SQL for a SELECT statement matching the kwargs passed. """
    sql = list()
    sql.append("SELECT * FROM %s " % table)
    if kwargs:
        sql.append("WHERE " + " AND ".join("%s = '%s'" % (k, v) for k, v in kwargs.iteritems()))
    sql.append(";")
    return "".join(sql)


def upsert(table, **kwargs):
    """ update/insert rows into objects table (update if the row already exists)
        given the key-value pairs in kwargs """
    keys = ["%s" % k for k in kwargs]
    values = ["'%s'" % v for v in kwargs.values()]
    sql = list()
    sql.append("INSERT INTO %s (" % table)
    sql.append(", ".join(keys))
    sql.append(") VALUES (")
    sql.append(", ".join(values))
    sql.append(") ON DUPLICATE KEY UPDATE ")
    sql.append(", ".join("%s = '%s'" % (k, v) for k, v in kwargs.iteritems()))
    sql.append(";")
    return "".join(sql)


def delete(table, **kwargs):
    """ deletes rows from table where **kwargs match """
    sql = list()
    sql.append("DELETE FROM %s " % table)
    sql.append("WHERE " + " AND ".join("%s = '%s'" % (k, v) for k, v in kwargs.iteritems()))
    sql.append(";")
    return "".join(sql)

你就是这样使用它的。只需给它一个表名和一个字典(或使用 python 的 **kwargs 功能):

>>> upsert("tbl", LogID=500, LoggedValue=5)
"INSERT INTO tbl (LogID, LoggedValue) VALUES ('500', '5') ON DUPLICATE KEY UPDATE LogID = '500', LoggedValue = '5';"

>>> read("tbl", **{"username": "morten"})
"SELECT * FROM tbl WHERE username = 'morten';"

>>> read("tbl", **{"user_type": 1, "user_group": "admin"})
"SELECT * FROM tbl WHERE user_type = '1' AND user_group = 'admin';"

但要小心 SQL 注入攻击

看看当你的代码的恶意用户这样做时会发生什么:

>>> read("tbl", **{"user_group": "admin'; DROP TABLE tbl; --"})
"SELECT * FROM tbl WHERE user_group = 'admin'; DROP TABLE tbl; --';"

制作你自己的临时 ORM 很容易,但你只能得到你所看到的——你必须自己转义输入:)

【讨论】:

  • 这里对于插入语句,它总是在单引号内生成值。因此,此代码必须修改如下,``` keys = ["%s" % k for k in kwargs] # values = ["'%s'" % v for v in kwargs.values()] values = [] for value in kwargs.values(): if type(value) is str: values.append("'%s'" % (value)) elif value is None: values.append("%s" % (" ''")) else: values.append("%s" % value) ```
  • 在 Python 3+ 中,将 kwargs.iteritems() 替换为 kwargs.items()
【解决方案2】:

SQLAlchemy 提供a robust expression language 用于从 Python 生成 SQL。

然而,与所有其他精心设计的抽象层一样,它生成的查询通过绑定变量插入数据,而不是通过尝试混合查询语言和插入单个字符串的数据。这种方法避免了大量的安全漏洞,否则就是正确的选择。

【讨论】:

  • 链接已失效。我认为这是相关文件:docs.sqlalchemy.org/en/latest/core/expression_api.html
  • @phasetwenty,谢谢,已更新(五年后,呵呵)。
  • 我觉得它又死了
  • 更新为直接链接到 SQLAlchemy Core 文档的根目录。
  • 链接仍然有效!
【解决方案3】:

为了稳健性,我建议使用准备好的语句来发送用户输入的值,无论您使用什么语言。 :-)

【讨论】:

  • 是否已经有图书馆可以这样做?我想要纯 sql 语句作为输出虽然:)
【解决方案4】:

python db api 2.0 有一个用于连接对象的“.execute”方法。您可以使用此函数指定参数(使用逗号而不是 % 符号将参数与查询字符串分开)。

【讨论】:

    【解决方案5】:

    通常手动引用参数是个坏主意。如果转义规则出现错误怎么办?如果转义与使用的 DB 版本不匹配怎么办?如果您只是忘记转义某些参数或错误地认为它不能包含需要转义的数据怎么办?这一切都可能导致 SQL 注入漏洞。此外,当您需要为 LOB 列传递大数据块时,DB 可能对 SQL 语句长度有一些限制。这就是为什么 Python DB API 和大多数数据库(Python DB API 模块将透明地转义参数,如果数据库不支持这一点,就像早期的 MySQLdb 所做的那样)允许传递与语句分开的参数:

    .execute(操作[,参数])

    【讨论】:

    • 我明白,但我只想要一个 sql 语句列表(不执行它们)
    猜你喜欢
    • 2017-11-16
    • 2014-06-08
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-04-03
    • 2019-06-14
    • 2020-12-06
    相关资源
    最近更新 更多