Warning: file_get_contents(/data/phpspider/zhask/data//catemap/5/sql/68.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Python 在SQLAlchemy中手动构建SQL查询时,如何正确转义字符串?_Python_Sql_Sqlalchemy_Escaping - Fatal编程技术网

Python 在SQLAlchemy中手动构建SQL查询时,如何正确转义字符串?

Python 在SQLAlchemy中手动构建SQL查询时,如何正确转义字符串?,python,sql,sqlalchemy,escaping,Python,Sql,Sqlalchemy,Escaping,我使用SQLAlchemy连接到Python中的不同数据库,但并没有使用ORM支持,因为这由于几个原因而无法实现 我主要使用以下方法构建复杂的SQL查询 sql += "AND fieldname = '%s'" % myvar 在我的例子中,SQL注入不是一个问题,因为数据总是来自一个可信的源,但即使源是可信的,它也可能包含一些可能破坏查询的字符,如,%或 主要是,我需要对它们进行转义,我想知道是否有一个已经存在的转义函数可以重复使用。您不应该尝试实现自己的转义,而是应该使用SQLAlche

我使用SQLAlchemy连接到Python中的不同数据库,但并没有使用ORM支持,因为这由于几个原因而无法实现

我主要使用以下方法构建复杂的SQL查询

sql += "AND fieldname = '%s'" % myvar
在我的例子中,SQL注入不是一个问题,因为数据总是来自一个可信的源,但即使源是可信的,它也可能包含一些可能破坏查询的字符,如
%


主要是,我需要对它们进行转义,我想知道是否有一个已经存在的转义函数可以重复使用。

您不应该尝试实现自己的转义,而是应该使用SQLAlchemy的内置方法:

sql = 'select * from foo where fieldname = :name'
result = connection.execute(sql, name = myvar)

您可以使用pymysql中的escape_string方法,然后使用escape
,这样SQLAlchemy就不会尝试为该变量绑定参数,下面是示例

import MySQLdb
query = """ insert into.... values("{}"...) """.format(MySQLdb.escape_string(item).replace(':','\:'))
请注意,如果使用这种方式,则代码容易受到SQL注入的攻击

要安装
pymysql

pip3 install pymysql

编辑并完成其他贡献者的答案

编写直接SQL字符串通常是一个糟糕的解决方案,因为每个数据库系统都支持自己的SQL方言,因此SQL字符串通常不能跨数据库移植

为了将这个问题从用户那里抽象出来,SQLAlchemy邀请您以一种更面向对象的方式在稍高的级别编写SQL查询。它被称为SQL表达式语言,并记录在这里:

基本上,您可以用Python构建描述您想要做什么的表达式,SQLAlchemy将为您生成相应的SQL字符串,使用您正在使用的数据库的适当方言

由于您熟悉SQL,您可以在一个小时内学会这种“迷你语言”(我不太愿意在这里加个“s”)

如果我相信@BrtH,那么使用这个系统也会透明地为您转义字符串。 逃避是很难做到的,因此,把它留给一个成熟的系统总比自己去做要好

下面是select子句的随机示例:

from sqlalchemy import select
...
ham_table = meta.tables['ham']
sel = select([ham_table.c.size, ham_table.c.weight]).where(ham_table.c.taste == 'yummy')
result = meta.bind.execute(sel)

不要被“.c.”所抛弃,这只是一个惯例,可以帮助他们很好地为您实现自动化。它们基本上为您生成列描述符,并将它们存储在表对象的.c字段下。

如果必须显式转义字符串,并且标准工具不符合要求,您可以使用引擎的方言请求
SQLAlchemy
转义

导入sqlalchemy
engine=sqlalchemy.create_引擎(…)
sqlalchemy.String(“”).literal_处理器(方言=引擎.dial)(value=“untrusted value”)

在我的例子中,我需要根据用户输入动态创建一个数据库(
sqlalchemy-utils
具有此功能,但在我的例子中失败)。

扩展@edd的答案,该答案在有限的容量下工作

@edd提供:

import sqlalchemy

engine = sqlalchemy.create_engine(...)
sqlalchemy.String('').literal_processor(dialect=engine.dialect)(value="untrusted value")
如果“不受信任的值”是要执行的查询,则最终将生成一个双引号字符串,该字符串包含一个单引号字符串,如果不去掉引号,则无法直接执行该字符串,即
“'SELECT…'”

您可以使用
sqlalchemy.Integer().literal\u processor
执行相同的操作,但结果不会有额外的内部引号,因为它旨在创建一个类似
5
的整数,而不是类似
'5'
的字符串。因此,您的结果将只被引用一次:
“选择…”

我发现这个整数方法有点粗略——读我代码的人会知道我为什么这么做吗?至少对于psycopg2来说,有一种更直接、更清晰的方法

如果您的底层驱动程序是psycopg2,则可以使用sqlalchemy深入驱动程序,获取光标,然后使用psycopg2的
cursor.mogrify
绑定并转义查询

from sqlalchemy.orm import sessionmaker

Session = sessionmaker(bind=engine)
session = Session()
cursor = session.connection().connection.cursor()
processed_query = cursor.mogrify([mogrify args, see docs]).decode("UTF-8")
我从这个答案中得到了如何抓住光标:

从这个答案中,莫格里菲:

我的用例是构建一个查询,然后将其包装成parantises和别名,如
(SELECT…)作为temp\u some\u table
,以便将其传递给PySpark JDBC
read
。当SQLAlchemy构建查询时,它会最小化括号,因此我只能得到
SELECT。。。作为临时表格
。我使用上述方法获得我需要的:

cursor = session.connection().connection.cursor()
aliased_query = cursor.mogrify(
    f"({query}) AS temp_{model.__tablename__}"
).decode("UTF-8")

@Ronny首先,他的问题是如何在sql查询中转义字符。这是正确的答案。其次,你真的认为你的评论对一年前的帖子有用吗???@BrtH不管是第二次还是一年前,其他用户仍在阅读答案。我今天还在读这篇文章,我不知道你们说的“sql表达式层”是的,此解决方案不允许使用
insert-INTO-table_name(col1,col2)值('col1','col2)
格式构建聚合插入=P为此,您确实需要在收集值之前真正地对其进行转义。@t对于这一点,还有比手动转义更好的方法。请注意,这可能不足以用于所有SQL方言。例如,
escape\u string
使用反斜杠来转义不适用于SQLite的引号。示例实际上并没有做任何事情。它只是用引号将“不可信值”放入“不可信值”。当然,你需要用一个恰当的例子来说明,更不用说,这并不能解释你将如何编写一个“SELECT*FROM:table_dynamic”类型的东西。