如果在 where 语句中传递字符串,则python模块cx_Oracle要求参数化参数。我正在读取文件中的查询,这些查询看起来就像是如何从像sql developer这样的IDE执行它们。
示例查询
select name, count(1) from employees where status = 'Active' and role= 'Manager' group by name order by 1;
我想编写一些函数,将此查询作为输入,然后将参数作为元组吐出:
query = 'select name, count(1) from employees where status = :1 and role= :2 group by name order by 1;'
parms = ('Active','Manager')
这样我就可以在一个简单的函数中传递这两个来执行查询:
cursor_object.execute(query,parms)
不幸的是,我对正则表达方式感到难以置信,而且我已经在这方面努力了几个小时而无济于事。
答案 0 :(得分:2)
你走了:
import re
sql = """select name, count(1) from employees where status = 'Active' and role= 'Manager' group by name order by 1;"""
rx = re.compile(r"""\w+\s*=\s*'([^']+)'""")
params = rx.findall(sql)
print(params)
# ['Active', 'Manager']
主要部分是
\w+\s*=\s*'([^']+)'
分解,这说:
\w+\s* # 1+ word characters, 0+ whitespace characters
=\s* # =, 0+ whitespace characters
'([^']+)' # '(...)' -> group 1
<小时/>
要同时使用查询和参数,您可以编写一个小函数:
import re
sql = """select name, count(1) from employees where status = 'Active' and role= 'Manager' group by name order by 1;"""
rx = re.compile(r"""(\w+\s*=\s*)'([^']+)'""")
def replacer(match):
replacer.params.append(match.group(2))
return '{}:{}'.format(match.group(1), len(replacer.params))
replacer.params = list()
query = rx.sub(replacer, sql)
params = replacer.params
print(query)
print(params)
# select name, count(1) from employees where status = :1 and role= :2 group by name order by 1;
# ['Active', 'Manager']
如评论中所述,您需要为要分析的每个查询重置参数列表。
答案 1 :(得分:1)
快速而肮脏的解决方案是编写与引用字符串匹配的RegEx。你可以这样开始:
import re
import textwrap
query = textwrap.dedent("""\
select name, count(1)
from employees
where status = 'Active' and role= 'Manager'
group by name order by 1;""")
sub_var = re.compile(r"'[^']+'").sub
print(sub_var("VAR", query))
# select name, count(1)
# from employees
# where status = VAR and role= VAR
# group by name order by 1;
但是,在这里你需要替换一个为每次匹配增加自身的值。
要做到这一点,你需要一个功能。请记住,re.sub
可以将可调用作为替换刺。 callable必须将MatchObject作为参数并返回替换。
在这里,我更喜欢使用可调用的类:
class CountVar(object):
def __init__(self):
self.count = 0
def __call__(self, mo):
self.count += 1
return ":{0}".format(self.count)
print(sub_var(CountVar(), query))
# select name, count(1)
# from employees
# where status = :1 and role= :2
# group by name order by 1;
这是!
答案 2 :(得分:0)
Jan的答案唯一的问题是它不会生成带有&#34;:1&#34;,&#34;:2&#34;等所需的字符串。
以下内容应该有效:
import re
i=1
pattern = r"(?<==\s*)'\w+'"
params = []
while True:
match = re.find( pattern, cmd )
if match is None: break
params.append(match.group())
cmd = re.sub( pattern, ":" + str(i), 1 )
i += 1
在模式中,(?<=)
被称为正向lookbehind并确保参数(在这种情况下为=\s*
,等于后跟任意数量的空格)出现在匹配的部分之前,但它不包含在匹配中(因此它不会包含在params
中或在替换中被替换)。