SQLAlchemy不区分大小写的基于IN的搜索查询?

6

如何在SQLAlchemy ORM中进行安全的不区分大小写的IN搜索?

我和我的团队成员都在寻找这个答案,但似乎没有找到符合我们需求的方法。

在原始的SQL中,我可以这样做:

 SELECT * FROM TABLENAME WHERE UPPER(FIELDNAME) IN (UPPER('foo'), UPPER('bar'));

如果FOO和BAR不是用户输入的未知情况下,我很担心以下问题:

  1. 安全性:我不想遭受Bobby Tables(http://xkcd.com/327/)的访问,也找不到告诉我如何在SQLAlchemy中转义字符串的文档,如果我连接字符串会感觉更安全(但仍然感觉不舒服)。
  2. 速度主要由索引处理,但显然,在发出查询之前在RAM中进行大小写校正比告诉数据库执行更快,因此,除非我真的需要,否则不会在查询中使用UPPER。上面的方法是展示我想做的事情的最佳方式。但它不应该做任何疯狂的事情。
  3. 平台无关代码。我将在多个数据库类型上运行它,并且只要我有发言权,就会完全测试它,我不希望查询被绑定到特定的SQL对话框上。毕竟,这就是我使用SQLAlchemy的原因。:)

如果有帮助,由于我们使用其他库,我们目前绑定到SQLAlchemy 8.4版本。

1个回答

11

这应该完全编译...

query( models.Object )\
.filter( 
     sqlalchemy.func.upper( models.Object.fieldname )\
     .in_( (sqlalchemy.func.upper(foo) , sqlalchemy.func.upper(bar), ) )
)\
.all()

  1. 你也可以直接传入大写文本。个人建议使用 in_( foo.uppercase() , bar.uppercase() )

  2. SqlAlchemy 通过 DBAPI 将绑定参数传递到后端数据存储器。简而言之,值会自动转义。


如果您想要一个字符串列表,可以尝试像这样的代码:

.in_( [ i.upper() for i in inputs ] )
.in_( [ sqlalchemy.func.upper(i) for i in inputs ] )

只是想补充一下,如果你想优化这些选择速度,并且使用的是Postgres或Oracle数据库,可以创建一个“函数索引”


CREATE INDEX table_fieldname_lower_idx ON table(lower(fieldname))

数据库中的查询规划器将知道在针对 lower(fieldname) 查询时使用 lower(fieldname) 索引。


那如果我的输入是一个字符串列表呢? - honestduane
我的第一篇帖子使用了错误的语法。in_ 需要一个可迭代对象。因此,您可以简单地使用列表、列表解析、生成器、lambda/map等来替换它。 - Jonathan Vanasco
1
我将把这个设置为答案;我的团队和Bobby Table的母亲都感谢你。 - honestduane
谢谢。我应该补充说,进行小写比较/存储通常更适合调试 - 它往往比大写对于人眼更易读。 - Jonathan Vanasco
是的,但是字符集排序规则的问题在于它是平台特定的问题,而我们正在尽可能地使其与平台无关。 - honestduane

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接