【问题标题】:Autogenerate SQL statements from ragged Python dictionary从不规则的 Python 字典中自动生成 SQL 语句
【发布时间】:2021-03-02 03:55:19
【问题描述】:

我正在尝试遍历一个字典来自动生成 SQL WHERE 语句。下面是 dict 的示例以及所需的输出(已针对逻辑 OR/AND 运算符的使用进行了优化)。

有 5 个字段需要过滤(即 field1、field2、field3、field4、value5)。 dict 将过滤每个字段的值存储在元组中(其中 tuple[0] 和 tuple[1] 表示为过滤范围的下限和上限)。

您会在所需的输出(见下文)中注意到逻辑运算符已经过优化以消除任何冗余。例如,对于 GROUP1,field1 和 field2 的值(即分别为 40000 到 50000 和 0000 到 ZZZZ)在 WHERE 语句中只被引用一次,并且后跟一个 AND 运算符和一系列过滤器,其中 field3(及其对应的field4/field5 过滤器)由 OR 运算符分隔(即它在 field3 中需要过滤“分叉”和逻辑 OR 运算符)。对于 GROUP2,存在类似的结构;然而,field2 是这个“叉子”出现的地方。

input_range_dict = {
    "GROUP1": {
        (40000, 50000): { # field1
            ("0000", "ZZZZ"): { # field2
                ("000", "ZZZ"): { # field3
                    ("10000000", "99999999"): # field4
                         [(123, 123), (456, 456)], # field5 
                    ("20000000", "40000000"): # field4
                         [("000", "ZZZ")]}, # field5
                ("AAA", "BBB"): { # field3
                    ("10000000", "99999999"): # field4
                         [("000", "ZZZ")]} # field5
                               }
                         }
                },
    "GROUP2": {
        (70000, 90000): {
            ("0000", "ZZZZ"): { 
                ("000", "ZZZ"): {
                    ("10000000", "99999999"):
                         [(123, 123), (456, 456)],
                    ("20000000", "40000000"):
                         [("000", "ZZZ")]},
            ("AAAA", "ZZZZ"): {
                ("AAA", "BBB"): {
                    ("10000000", "99999999"):
                         [("000", "ZZZ")]}
                               }
                         }
                }
        }
}

GROUP1 的输出字符串:

WHERE
  field1 BETWEEN "40000" AND "50000"
  AND field2 BETWEEN "0000" AND "ZZZZ"
  AND
    (
      (
        field3 BETWEEN "000" AND "ZZZ"
        AND
          (
            (
              field4 BETWEEN "10000000" AND "99999999"
              AND
                (
                  field5 BETWEEN "123" AND "123"
                  OR field5 BETWEEN "456" AND "456"
                 )
             )
             OR
             (
               field4 BETWEEN "20000000" AND "40000000"
               AND field5 BETWEEN "000" AND "ZZZ"
              )
           )
       )
       OR
       (
         field3 BETWEEN "AAA" AND BBB"
         AND field4 BETWEEN "10000000" AND "99999999"
         AND field5 BETWEEN "000" AND "ZZZ"
       )        
    )  

GROUP2 的输出字符串:

WHERE
  field1 BETWEEN "70000" AND "90000" 
  AND 
    (
      field2 BETWEEN "0000" AND "ZZZZ"
      AND field3 BETWEEN "000" AND "ZZZ"
      AND
        ( 
          (
            field4 BETWEEN "10000000" AND "99999999"
            AND
              (
                 field5 BETWEEN "123" AND "123"
                 OR field5 BETWEEN "456" AND "456"
              )
           )
           OR
           (
             field4 BETWEEN "20000000" AND "40000000"
             AND field5 BETWEEN "000" AND "ZZZ"
           )
         )
      )
   OR
    (
      field2 BETWEEN "AAAA" AND "ZZZZ"
      AND field3 BETWEEN "AAA" AND "BBB"
      AND field4 BETWEEN "10000000" AND "99999999"
      AND field5 BETWEEN "000" AND "ZZZ"
     )
    

【问题讨论】:

    标签: python


    【解决方案1】:

    这是一个基于组结构形成条件逻辑但没有漂亮打印的解决方案:

    def gen_sql(d, c = 1, l = 0):
       if isinstance(d, list):
          return ("" if len(d) < 2 else "(")+ ' or '.join(f'field{c} between {a} and {b}' for a, b in d)+ ("" if len(d) < 2 else ")")
       return ' or '.join(("" if len(d) < 2 else "(")+f'field{c} between {a} and {b} and {gen_sql(k, c = c+1, l = l+(len(d) > 1))}'+("" if len(d) < 2 else ")") for (a, b), k in d.items())
       
    input_range_dict = {'GROUP1': {(40000, 50000): {('0000', 'ZZZZ'): {('000', 'ZZZ'): {('10000000', '99999999'): [(123, 123), (456, 456)], ('20000000', '40000000'): [('000', 'ZZZ')]}, ('AAA', 'BBB'): {('10000000', '99999999'): [('000', 'ZZZ')]}}}}, 'GROUP2': {(70000, 90000): {('0000', 'ZZZZ'): {('000', 'ZZZ'): {('10000000', '99999999'): [(123, 123), (456, 456)], ('20000000', '40000000'): [('000', 'ZZZ')]}}, ('AAAA', 'ZZZZ'): {('AAA', 'BBB'): {('10000000', '99999999'): [('000', 'ZZZ')]}}}}}
    for a, b in input_range_dict.items():
        print(f'{a}:')
        print(gen_sql(b))
        print()
    

    输出:

    GROUP1:
    field1 between 40000 and 50000 and field2 between 0000 and ZZZZ and (field3 between 000 and ZZZ and (field4 between 10000000 and 99999999 and (field5 between 123 and 123 or field5 between 456 and 456)) or (field4 between 20000000 and 40000000 and field5 between 000 and ZZZ)) or (field3 between AAA and BBB and field4 between 10000000 and 99999999 and field5 between 000 and ZZZ)
    
    GROUP2:
    field1 between 70000 and 90000 and (field2 between 0000 and ZZZZ and field3 between 000 and ZZZ and (field4 between 10000000 and 99999999 and (field5 between 123 and 123 or field5 between 456 and 456)) or (field4 between 20000000 and 40000000 and field5 between 000 and ZZZ)) or (field2 between AAAA and ZZZZ and field3 between AAA and BBB and field4 between 10000000 and 99999999 and field5 between 000 and ZZZ)
    

    注意GROUP2 的字典值的格式不完全符合您所需的输出:}, 需要放在键 ("AAAA", "ZZZZ") 之前。

    【讨论】:

      猜你喜欢
      • 2021-12-03
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2016-09-09
      • 2011-10-26
      • 1970-01-01
      • 2010-12-06
      相关资源
      最近更新 更多