使用 sqlparse 解析 CASE WHEN 语句

2024-03-18

我有以下 SQL 查询并想使用它来解析它sqlparse https://github.com/andialbrecht/sqlparse

import sqlparse

query =  """
select SUM(case when(A.dt_unix<=86400
                     and B.flag="V") then 1
           end) as TEST_COLUMN_1,
       SUM(case when(A.Amt - B.Amt > 0
                     and B.Cat1 = "A"
                     and (B.Cat2 = "M"
                          or B.Cat3 = "C"
                          or B.Cat4 = "B")
                     and B.Cat5 is NULL) then 1
           end) as TEST_COLUMN_2
from test_table A
left join test_table_2 as B on A.ID=B.ID
where A.DT >B.DT
group by A.ID
"""

query_tokens = sqlparse.parse(query)[0].tokens
print(query_tokens)

将给出 SQL 语句中包含的所有标记:

[<Newline ' ' at 0x7FAA62BD9F48>, <DML 'select' at 0x7FAA62BE7288>, <Whitespace ' ' at 0x7FAA62BE72E8>, <IdentifierList 'SUM(ca...' at 0x7FAA62BF7CF0>, <Newline ' ' at 0x7FAA62BF6288>, <Keyword 'from' at 0x7FAA62BF62E8>, <Whitespace ' ' at 0x7FAA62BF6348>, <Identifier 'test_t...' at 0x7FAA62BF7570>, <Newline ' ' at 0x7FAA62BF64C8>, <Keyword 'left j...' at 0x7FAA62BF6528>, <Whitespace ' ' at 0x7FAA62BF6588>, <Identifier 'test_t...' at 0x7FAA62BF7660>, <Whitespace ' ' at 0x7FAA62BF67C8>, <Keyword 'on' at 0x7FAA62BF6828>, <Whitespace ' ' at 0x7FAA62BF6888>, <Comparison 'A.ID=B...' at 0x7FAA62BF7B10>, <Newline ' ' at 0x7FAA62BF6B88>, <Where 'where ...' at 0x7FAA62BF28B8>, <Keyword 'group' at 0x7FAA62BD9E88>, <Whitespace ' ' at 0x7FAA62BD93A8>, <Keyword 'by' at 0x7FAA62BD9EE8>, <Whitespace ' ' at 0x7FAA62C1CEE8>, <Identifier 'A.ID' at 0x7FAA62BF2F48>, <Newline ' ' at 0x7FAA62BF6C48>]

我如何解析这些令牌以便处理CASE WHEN语句的方式使我可以提取所有条件并保持通过使用括号定义的优先级。我在文档中找不到任何相关示例。

对此有什么想法吗?


该项目确实有点缺乏记录。我看了看examples https://github.com/andialbrecht/sqlparse/tree/master/examples并稍微扫描了一下源代码。不幸的是,该文档并未包含所有方法Token and TokenList对于此任务有用的类。

例如,一个重要但被忽略的方法是TokenList.get_sublists() method https://github.com/andialbrecht/sqlparse/blob/47768597924d88cec426e379b4afae8b58491956/sqlparse/sql.py#L201-L204,它可以让您比其他方法更轻松地遍历嵌套标记列表;这TokenList.flatten() https://sqlparse.readthedocs.io/en/latest/analyzing/#sqlparse.sql.TokenList.flatten方法仅产生未分组的树中的标记,而CASE是一个分组令牌,因此纯粹根据文档,您可能会发现很难使用解析的令牌树做一些有用的事情。

我在代码库中注意到的另一个方便的方法是TokenList._pprint_tree() method https://github.com/andialbrecht/sqlparse/blob/master/sqlparse/sql.py#L162-L178,它将当前令牌树转储到标准输出。当尝试编写分析树的代码时,这非常有帮助。

总而言之我的总体印象是sqlparse与其说它是一个解析库,不如说它是一个重新格式化 SQL 的工具。它包括一个很好的解析器,但不包括制作所需的工具一般使用它所产生的树。

图书馆真正缺少的是一个基地节点访问者类例如由Python ast module https://docs.python.org/3/library/ast.html#ast.NodeVisitor,或者树节点遍历器,又像ast模块提供 https://docs.python.org/3/library/ast.html#ast.walk。幸运的是,这两种方法都很容易自己构建:

from collections import deque
from sqlparse.sql import TokenList

class SQLTokenVisitor:
    def visit(self, token):
        """Visit a token."""
        method = 'visit_' + type(token).__name__
        visitor = getattr(self, method, self.generic_visit)
        return visitor(token)

    def generic_visit(self, token):
        """Called if no explicit visitor function exists for a node."""
        if not isinstance(token, TokenList):
            return
        for tok in token:
            self.visit(tok)

def walk_tokens(token):
    queue = deque([token])
    while queue:
        token = queue.popleft()
        if isinstance(token, TokenList):
            queue.extend(token)
        yield token

现在您可以使用其中之一来访问Case nodes:

statement, = sqlparse.parse(query)

class CaseVisitor(SQLTokenVisitor):
    """Build a list of SQL Case nodes

      The .cases list is a list of (condition, value) tuples per CASE statement

    """
    def __init__(self):
        self.cases = []

    def visit_Case(self, token):
        branches = []
        for when, then_ in token.get_cases():
            branches
        self.cases.append(token.get_cases())

visitor = CaseVisitor()
visitor.visit(statement)
cases = visitor.cases

or

statement, = sqlparse.parse(query)

cases = []
for token in walk_tokens(statement):
    if isinstance(token, sqlparse.sql.Case):
        cases.append(token.get_cases())

之间的区别walk_tokens() and NodeVisitor在此示例中,模式可以忽略不计,但我们只是简单地为每个模式提取单独的标记CASE语句,不处理WHEN ... THEN ...代币。在里面NodeVisitor模式,您可以在当前访问者实例上设置更多属性来“切换齿轮”,并在更多中捕获有关这些子树标记的更多信息visit_....方法,这可能比嵌套更容易遵循for循环生成器。

另一方面,随着walk_tokens()生成器,如果您创建一个单独的变量来引用生成器,则可以将迭代移交给辅助函数:

all_tokens = walk_tokens(stamement)
for token in walk_tokens(statement):
    if isinstance(token, sqlparse.sql.Case):
        branches = extract_branches(all_tokens)

where extract_branches将进一步迭代,直到到达 case 语句的末尾。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

使用 sqlparse 解析 CASE WHEN 语句 的相关文章

  • 递归单元测试发现

    我有一个带有目录 tests 的包 我在其中存储单元测试 我的包裹看起来像 LICENSE models init py README md requirements txt tc py tests db test employee py
  • 查找公因数以将浮点数列表转换为整数列表

    我有一个来自其他函数的浮点数列表 我所知道的是 在理想世界中存在一个共同因素 可用于将每一项相乘以获得整数列表 可能存在一些小的数值噪声 1e 14 例如 2 3333333333333335 4 666666666666667 1 0 1
  • Python - Pandas - 将特定函数应用于给定级别 - 多索引数据帧

    我有一个多索引 DataFrame 并且我希望仅对分配给我的级别之一的向量应用一些计算 使用下面的代码 import pandas as pd import datetime ticker date US datetime date tod
  • 使用 pycharm 进行交互式 shell 调试

    我是 PyCharm 新手 我已经使用 IDLE 很长时间了 在IDLE中执行脚本后使用Python对象非常方便 有没有办法在使用 PyCharm 与交互式 python shell 执行后使用脚本对象 例如 我们有一个 测试 项目 其中包
  • 回归模型 statsmodel python

    这更多是一个统计问题 因为代码运行良好 但我正在学习 python 中的回归建模 我在下面使用 statsmodel 编写了一些代码来创建一个简单的线性回归模型 import statsmodels api as sm import num
  • 使用 PyQt 和 matplotlib 在可滚动小部件中显示多个绘图

    由于我没有得到答案this https stackoverflow com questions 12179893 creating a scrollable multiplot with pythons pylab我尝试用 PyQt 解决这
  • lxml/python 使用 CDATA 部分读取 xml

    在我的 xml 中我有一个CDATA部分 我想保留 CDATA 部分 然后剥离它 有人可以帮忙解决以下问题吗 默认不起作用 from io import StringIO from lxml import etree xml
  • python-messaging 无法处理 HTTP 请求

    我正在使用下面的代码尝试使用 python messaging 发送彩信https github com pmarti python messaging blob master doc tutorial mms rst https gith
  • 如何在pandas中分组后从每组中选择前n行? [复制]

    这个问题在这里已经有答案了 我有一个具有以下形状的 pandas 数据框 open year open month type col1 col2 我想找到每个 年 月 中的顶级类型 所以我首先找到每个 年 月 中每种类型的计数 freq d
  • 使用 selenium 和 firefox 保存图像

    我正在尝试使用 selenium 服务器和 python 客户端从网站保存图像 我知道图像的 URL 但我无法找到保存它的代码 无论是当它是文档本身还是当它嵌入到当前浏览器会话中时 到目前为止我找到的解决方法是保存页面的屏幕截图 有两种硒方
  • CTRL-C 在 Python 中的行为有所不同

    I ve recently started learning Python long time Java programmer here and currently in the process of writing some simple
  • 使用 python 更改目录

    我碰巧发现我无法从 python 代码中更改实际目录 我的测试程序如下 from os import system def sh script system bash c s script sh cd home sh pwd 的输出pwd
  • 使用Python构建caffe(找不到-lboost_python3)

    我正在尝试用 python 构建 caffe 但它一直这样说 CXX LD o python caffe caffe so python caffe caffe cpp usr bin ld cannot find lboost pytho
  • 如何让 IPython 按类别组织制表符补全的可能性?

    当一个对象有数百个方法时 制表符补全很难使用 通常 有趣的方法是由被检查对象的类而不是其基类定义或重写的方法 如何让 IPython 对其制表符完成可能性进行分组 以便首先检查对象的类中定义的方法和属性 然后是基类中的方法和属性 看起来像是
  • 为什么Python安装程序不断弹出?

    每当我尝试运行 Python 文件时 都会自动弹出此窗口 虽然 我可以关闭它 但有时它会连续打开 7 10 个窗口 这令人恼火 谁能告诉我为什么会发生这种情况 None
  • Python Sqlite3 获取 Sqlite 连接路径

    给定一个 sqlite3 连接对象 如何检索 sqlite3 文件的文件路径 The Python 连接对象 http github com python cpython blob master Modules sqlite connect
  • 将 scipy 稀疏矩阵的几行采样到另一个中

    如何对 scipy 稀疏矩阵的某些行进行采样 并从这些采样的行中形成一个新的 scipy 稀疏矩阵 例如 如果我有一个 10 行的 scipy 稀疏矩阵 A 并且我想创建一个新的 scipy 稀疏矩阵 B 其中 A 的第 1 3 4 行 该
  • 将 pi 打印到小数点后几位

    w3resources 面临的挑战之一是将 pi 打印到小数点后 n 位 这是我的代码 from math import pi fraser str pi length of pi number of places raw input En
  • Python 单元测试:Nose 失败时重试?

    我有一个随机失败的测试 我想让它在发送错误消息之前重试多次 我将 python 与 Nose 一起使用 我写了以下内容 但不幸的是 即使使用 try except 处理 当第一次尝试测试失败时 Nose 也会返回错误 def test so
  • python 根据日期创建目录结构

    我使用以下函数根据今天的日期创建目录 usr bin python import time datetime os today datetime date today todaystr today isoformat os mkdir to

随机推荐

  • 在php中注释局部变量

    我正在使用 Eclipse PDT 并且想使用 Phpdoc 注释局部变量 我所看到的是我可以使用注释类的变量 属性 var甚至 property 但是对于局部变量来说这怎么可能呢 我怎样才能做这样的事情 function foo var
  • 从 int* 转换后,我的 char 指针指向无效值

    我正在学习C语言 我刚刚开始学习带指针的数组 我在这个问题上有问题 我希望输出必须是5但它是2 谁能解释一下为什么吗 int main int arr 1 2 3 4 5 char ptr char arr printf d ptr 4 r
  • 如何使 .svc 文件写入 asp.net Trace.axd

    我想弄清楚如何使 IIS 下托管的 3 5 WCF 服务写入 asp net 跟踪 我的猜测是您会将其添加到 web config 文件中
  • 如何更改 Xamarin.Forms 上的后退按钮文本

    我一直在尝试更改 Xamarin Forms 中后退按钮的文本 但没有成功 我已经尝试过这段代码但没有运气 NavigationPage SetBackButtonTitle this 我正在使用一个MasterDetailPage 我尝试
  • 如何消除 XCode 5 / iOS 7 中的图标眩光?

    我正在使用 XCode 5 开发者预览版来创建 iOS 7 应用程序 在iOS 7中 图标的眩光效果不再存在 没关系 但现在 当我在 iOS 6 设备 或模拟器 上运行由 XCode 5 编译的应用程序时 我看到图标上有眩光效果 禁用眩光的
  • 尝试为 linq 中的日期创建大于、等于或大于动态过滤器

    我一直在尝试为 Linq 创建一个表达式树过滤器 它接受 2 个日期和一串可能的值 小于 等于 大于 我希望将调用格式设置为 Query Where CompareDates x gt x left right less than 我有代码
  • 从标准输入读取密码[重复]

    这个问题在这里已经有答案了 场景 一个交互式 CLI Python 程序 需要密码 这也意味着 没有可能的 GUI 解决方案 在 bash 中 我可以读取密码 而无需在屏幕上重新提示 read s Python 有类似的东西吗 IE pas
  • 如何上传到 Dropbox Public 文件夹并获取公共 URL?

    我遇到一种情况 我需要将文件上传到我的 Dropbox 公共文件夹 并且上传后我需要存储上传文件的公共 url 我正在使用 python 对此的任何帮助都会很棒 Thanks 使用它在您的程序中设置 Python SDK https www
  • iOS 推送通知问题

    我正在做一个项目 其中推送通知功能是关键特征之一 当我在应用程序中时它工作正常 我收到通知并处理该通知 但问题是当我在后台并收到通知时 我在应用程序图标上看到徽章 当我单击该图标时 我的应用程序正在启动 但是didReceiveRemote
  • 在 ASP.Net Core 中创建自定义 HTML 帮助器

    我想创建自己的自定义 HTML Helper 就像 ASP NET MVC 中使用的那样 但我一直无法找到如何以正确的方式实现它们 我已经找到了如何创建自定义标记帮助程序 但没有找到 HTML 帮助程序 如何创建我自己的自定义 HTML 帮
  • 从 onLoadFinished() 中的光标填充小部件

    我想知道如何使用CursorLoader填充屏幕上的小部件 网上的所有示例仅适用于使用适配器 而且效果很好 我需要的是一种可靠的方法来从光标和 UI 线程上更新屏幕中的视图 并且有时不会因为以下原因而崩溃StaleDataException
  • 它有一些专门针对 tibble 和管道内衬副作用的函数吗?

    我想知道是否可以使用 dplyr select dplyr mutate 或 dplyr transmute 等函数来调用副作用函数 我有步行 但不是来自同一家庭 tibble as tibble mtcars gt dplyr trans
  • Chrome for IOS 无法在 iframe 中正确打开新窗口

    我正在尝试在 iframe 内的 Chrome for iOS 中的新窗口中打开链接 但 Chrome for iOS 不会在新窗口中打开链接 而是浏览器在同一窗口中而不是在新窗口中打开链接 对于弹出窗口也是如此 很奇怪 Example 测
  • 带有不可见项目的微格式 hreview

    我正在一个网站上实现微格式的 hreview 部分 以供 Google 索引 http www google com support webmasters bin answer py answer 146645 http www googl
  • 确保文件在 JVM 退出时被删除

    即使 JVM 提前终止 File deleteOnExit 是否也能保证文件被删除 正如蒂姆 本德所说 File deleteOnExit 不保证文件确实被删除 但是 在 Unixish 系统 例如 Linux 或 OSX 上 可以删除临时
  • 如何在同一个存储库中保留/维护公共和私有代码? (在存储库托管处)

    我正在开发自己的项目 该项目分为两部分 A 内核 通用代码 公共部分 B 适用于专有协议等的代码 私有部分 可供我和一些授权人员使用 我想要存储库托管 可能是 github assembla 它允许在同一存储库中的公共和私有分支中工作 我不
  • 向 sqlite 数据库添加列

    我正在尝试将在 R 中生成的向量作为新列添加到 sqlite 表中 为此我想使用dplyr 我安装了最新的开发版本以及dbplyr根据这篇文章打包here https www r bloggers com dplyr 0 6 0 comin
  • 标签中可以包含任何类型的标签吗?

    是否有诸如 div div
  • Cakephp 2.0 和基本身份验证

    我已将我的应用程序从 CakePHP 1 3 升级到 2 0 4 以前 我只能在一个控制器中使用安全组件来模拟基本 HTTP 身份验证 我曾经做过这样的事情 this gt Auth gt allow array this gt Secur
  • 使用 sqlparse 解析 CASE WHEN 语句

    我有以下 SQL 查询并想使用它来解析它sqlparse https github com andialbrecht sqlparse import sqlparse query select SUM case when A dt unix