regex 最好的方式来编程编辑一个SQL查询?

5m1hhzi4  于 2023-06-25  发布在  其他
关注(0)|答案(3)|浏览(113)

我有一个SQL查询字典,其中键是视图的名称,值是查询,如下所示:

SELECT
  artists.first_name,
  artists.last_name,
  artist_sales.sales
FROM database.artists
JOIN (
    SELECT artist_id, SUM(sales_price) AS sales
    FROM database.sales
    GROUP BY artist_id
  ) AS artist_sales
  ON artists.id = artist_sales.artist_id;

我想做的是通过编程替换表名,这样它就可以变成像catalog.database.artistscatalog.database.sales这样的东西。因此,无论我有什么函数,我都会使用regex来查找FROM子句之后的内容,并编辑表名以在数据库名称之前包含catalog。对此有什么想法吗?

yqhsw0fo

yqhsw0fo1#

我使用fstrings:
取决于你如何填充字典,你可能需要将它 Package 在一个循环机制中,但我认为你想要的本质是这样的:

table_name_1 = 'database.artists' 
table_name_2 = 'database.sales' 

query = f'''
SELECT
  artists.first_name,
  artists.last_name,
  artist_sales.sales
FROM {table_name_1}
JOIN (
    SELECT artist_id, SUM(sales_price) AS sales
    FROM {table_name_2}
    GROUP BY artist_id
  ) AS {table_name_2}
  ON {table_name_1}.id = {table_name_2}.artist_id;
  '''

这将生成查询字符串:
艺术家的艺术家艺术家艺术家艺术家艺术家艺术家艺术家艺术家艺术家艺术家艺术家艺术家艺术家艺术家艺术家艺术家艺术家艺术家艺术家艺术家艺术家艺术家艺术家艺术家艺术家艺术家艺术家艺术家艺术家艺术家艺术家艺术家艺术家艺术家艺术家艺术家艺术家艺术家艺术家艺术家艺术家艺术家艺术家艺术家艺术家艺术家艺术家艺术家艺术家艺术家艺术家艺术家艺术家艺术家艺术家艺术家艺术家database.artists.id = database.sales.artist_id;
你也可以使用f-strings来定义table_name变量:

db = 'database_name'

table_name_1 = f'{db}.artists' 
table_name_2 = f'{db}.sales'

这些变量的值为"database_name. artists"和"database_name. sales"。
不确定这是否是完整的答案,但希望这能回答你所坚持的核心问题。
但是如果你必须在定义字典之后执行查找/替换,那么一种方法可以是遍历字典,并在每个字典上使用string. split()函数来拆分'FROM'上的查询,然后在拆分值之间重新连接从split函数生成的字符串列表和'FROM catalog.'。
你可以定义一个函数来拆分查询为'split_queries',然后使用:

new_dict = dict((k, split_queries(v)) for k, v in original_dict.items())

但是,这确实假设每个查询中的“FROM”之后只有一个空格。如果这不一定是真的,你会想用利用正则表达式的东西替换split_queries函数,此时,我不是你的人_()/抱歉。
希望至少有一部分对你有帮助。

c7rzv4ha

c7rzv4ha2#

由于FROM是SQL中的一个关键字,并且您可能希望无论如何都要更新它的每次出现,因此您可以执行简单的搜索并使用regex进行替换,搜索并捕获包含from(大写或非大写)及其尾随空格的不同短语,并将其替换为本身和您想要添加的数据库的名称。
例如:

import re

# queries = {...your queries...}
expr = re.compile(r"(\bfrom[\t ]+)", re.IGNORECASE)
repl = r"\1catalog."

for key in queries: queries[key] = re.sub(expr, repl, queries[key])
nfg76nw0

nfg76nw03#

不使用脆弱的正则表达式或直接的字符串替换,您可以使用SQL解析器(如sqlglot)在满足所需条件时对查询进行更新:

import sqlglot # pip3 install sqlglot

def update_query(ast, find_tbl, replace_tbl):
   if isinstance(ast, (sqlglot.expressions.From, sqlglot.expressions.Join)) and \
        isinstance(ast.this, sqlglot.expressions.Table): # check if expression is a `from` or `join` and its child value is a `table` expression
      if all((t if isinstance(t:=getattr(ast.this, a), str) else t.sql()) in b \
        for a, b in find_tbl.items()): # if the table meets the find criteria...
          for a, b in replace_tbl.items():
              ast.this.args[a] = b # ... run replacements
          return
   for i in getattr(ast, 'args', {}).values(): #recurse over the expression's children, in place
      if isinstance(i, list):
         for j in i: update_query(j, find_tbl, replace_tbl)
      else:
         update_query(i, find_tbl, replace_tbl)

d = {'view':'''SELECT
  artists.first_name,
  artists.last_name,
  artist_sales.sales
FROM database.artists
JOIN (
    SELECT artist_id, SUM(sales_price) AS sales
    FROM database.sales
    GROUP BY artist_id
  ) AS artist_sales
  ON artists.id = artist_sales.artist_id;'''} # your dictionary
 
for view, query in d.items():
   ast = sqlglot.parse_one(query) # convert string query to `sqlglot` AST object
   update_query(ast, {'this':['artists', 'sales'], 'db':['database']}, 
      {'catalog':'catalog'}) # run update in place
   d[view] = ast.sql(pretty = True) # replace old query with updated AST object

print(d['view'])

输出:

"""
SELECT
  artists.first_name,
  artists.last_name,
  artist_sales.sales
FROM catalog.database.artists
JOIN (
  SELECT
    artist_id,
    SUM(sales_price) AS sales
  FROM catalog.database.sales
  GROUP BY
    artist_id
) AS artist_sales
  ON artists.id = artist_sales.artist_id
"""

update_query的参数find_tblreplace_tbl的解释:
find_tbl:一个字典,包含目标表达式类型和一个潜在表达式非常匹配的值(在一个列表中
目标表达式的潜在字典键名:

  • "this":基表名称本身,即
database.**articles**
  • "db":数据库名称,即
**database**.articles
  • "catalog":目录名称,即
**catalog**.database.articles

replace_tbl:包含匹配表表达式的替换值(作为字符串)的字典:
目标表达式更新的潜在字典键名称:

  • "this":基表名称本身,即
database.**articles**
  • "db":数据库名称,即
**database**.articles
  • "catalog":目录名称,即
**catalog**.database.articles

相关问题