1

我有一个从 python 脚本运行的查询。它看起来像这样:

app_phone=str(5555555555)
query_string=""""select biz_name, biz_addr, biz_owner
from business_t
where regexp_replace(biz_phone_1, E'\\\\D|^1', '', 'g') = '"""+app_phone+"""'
or regexp_replace(biz_phone_2, E'\\\\D|^1', '', 'g') = '"""+app_phone+"""'
or regexp_replace(biz_cell_1, E'\\\\D|^1', '', 'g') = '"""+app_phone+"""'
or regexp_replace(biz_cell_2, E'\\\\D|^1', '', 'g') = '"""+app_phone+"""'
;"""
result=run_query(query_string)

查询运行良好-我的问题实际上是以易于阅读的格式“以语法方式”编写此类查询的最佳方法,该格式不会向脚本添加不必要的处理?或者这是写这个的好方法?

这看起来有点难看,但也许这只是代码中需要原始 SQL 的诅咒。

4

5 回答 5

1

我可以推荐以下选项:

1)我将直接在查询中嵌入查询参数,然后我将作为元组/字典单独传递给 cursor.execute(请参阅您的 db api 以了解确切的格式)方法:

app_phone = 5555555555
query_string="""SELECT biz_name, biz_addr, biz_owner
                 FROM business_t
                 WHERE regexp_replace(biz_phone_1, E'\\\\D|^1', '', 'g') = '%(phone)s'
                     OR regexp_replace(biz_phone_2, E'\\\\D|^1', '', 'g') = '%(phone)s'
                     OR regexp_replace(biz_cell_1, E'\\\\D|^1', '', 'g') = '%(phone)s'
                     OR regexp_replace(biz_cell_2, E'\\\\D|^1', '', 'g') = '%(phone)s';
             """
result = run_query(query_string, {'phone': app_phone})

该解决方案将使您免受(大多数)sql注入攻击

2) 要构建查询,您可以考虑使用 sql 查询构建库 ( https://pypi.python.org/pypi/python-sql/0.2 )。这将允许您根据表达式构建 SQL 查询,而不是使用字符串编辑。不确定此查询生成器是否支持在 where 中使用正则表达式

3)您可以尝试使用循环,但它是否变得更具可读性的问题将是主观的,恕我直言:

app_phone = 5555555555
cmp_phones = "regexp_replace(%s, E'\\\\D|^1', '', 'g') = '%%(phone)s'"
db_phone_columns = (biz_phone_1, biz_phone_2, biz_cell_1, biz_cell_2)
where_condition = 'OR'.join(cmp_phones % phone for phone in db_phone_columns)
result = run_query(query_string, {'phone': app_phone}
query_string="""SELECT biz_name, biz_addr, biz_owner
                 FROM business_t
                 WHERE %(where_condition)s;""" % 
             {'where_condition': where_condition}
result = run_query(query_string, {'phone': app_phone})

我个人认为解决方案 1) 最易读

4) 使用以电话为参数的存储过程

5) 示例中演示了我个人喜欢的查询字符串中的查询格式

于 2013-09-26T20:57:40.480 回答
1

我会这样做:

app_phone = 5555555555
query_string = r"""
    SELECT biz_name, biz_addr, biz_owner
    FROM   business_t
    WHERE  regexp_replace(biz_phone_1, E'\\D|^1', '', 'g') = '{0}'
        OR regexp_replace(biz_phone_2, E'\\D|^1', '', 'g') = '{0}'
        OR regexp_replace(biz_cell_1,  E'\\D|^1', '', 'g') = '{0}'
        OR regexp_replace(biz_cell_2,  E'\\D|^1', '', 'g') = '{0}'
    ;""".format(app_phone)
result = run_query(query_string)

请注意,我已将其设置为带有r前缀的原始字符串,以消除一级反斜杠转义。我认为使用该.format()功能总体上是在 Python 中进行字符串替换的最佳方法(当然比串联更好),特别是当您想要多次重复相同的替换值时。有些人可能会争辩说您应该使用有意义的名称而不是数字(即替换{0}为名称),这很好。有些人可能还认为您应该使用 SQL 的参数而不是 Python 的字符串替换,我认为这是个好建议。但是您似乎主要关注如何管理长字符串,尤其是连接,所以我的回答集中在使用 Python 的字符串功能上。

于 2013-09-26T21:37:48.920 回答
0

我通常通过排列 SQL 并为 SQL 术语使用大写来清理我的原始查询字符串:

app_phone = 5555555555
query_string = """SELECT biz_name, biz_addr, biz_owner
                  FROM   business_t
                  WHERE  regexp_replace(biz_phone_1, E'\\\\D|^1', '', 'g') = '"""+app_phone+"""'
                  OR     regexp_replace(biz_phone_2, E'\\\\D|^1', '', 'g') = '"""+app_phone+"""'
                  OR     regexp_replace(biz_cell_1, E'\\\\D|^1', '', 'g')  = '"""+app_phone+"""'
                  OR     regexp_replace(biz_cell_2, E'\\\\D|^1', '', 'g')  = '"""+app_phone+"""'
                  ;"""
result = run_query(query_string)
于 2013-09-26T17:48:28.483 回答
0

我没有从 Python 做太多 SQL,但在其他语言中,我只是按照该语言的任何约定整齐地安排了事情,这通常涉及逐行分解:

query_stmt = "SELECT stuff FROM tables ",
             "WHERE conditions = something"

我还在部分中构建了查询并将它们拼凑在一起,因此您最终会得到类似的结果:

queryStmt = "SELECT " + selectClause + " FROM " + fromClause + " WHERE " + whereClause

尽管我遇到了将查询放在一起并运行它的不同方法,但我从来没有对我以任何有效的组合字符串的方式组合查询而咆哮〜只要你正在创建一个有效的 SQL,在运行它时需要正确的引号和转义序列,你有余地让它看起来很漂亮。

于 2013-09-26T20:10:29.620 回答
0

好吧,您可以将其自动化一点,而不会增加太多开销:

val = '55555'
cols = ('biz_phone_1','biz_phone_2','biz_cell_1','biz_cell_2')
q = "SELECT biz_name, biz_addr, biz_owner FROM business_t WHERE "
q += ' OR '.join("regexp_replace({0}, E'\\\\D|^1', '', 'g') = '{1}'"
               .format(x,val)
               for x in  cols)

但是,您可能应该使用您的驱动程序应该支持的准备好的语句。

于 2013-09-26T20:35:02.727 回答