草庐IT

基于Python-sqlparse的SQL字段血缘追踪解析实现

fanstuck 2023-10-01 原文

目录

前言

一、字段血缘

1.区别字段

2.区别标识符序列

3.功能函数设定

二、字段血缘可视化

点关注,防走丢,如有纰漏之处,请留言指教,非常感谢


前言

SQL解析和血缘追踪的研究现在差不多可以告一段落了,从8月22日写HiveSQL源码之语法词法编译文件解析一文详解这篇文章以来便断断续续的对SQL语法解析研究,到了今天终于是有了一番成果。一般做此类研究的项目都是在数据治理和数据中台方面的服务作支撑,对于数据安全作用挺大的,多的内容我在上篇文章里面已经讲述了很多了,这里不再多提:

基于Python-sqlparse的SQL表血缘追踪解析实现,大家可以看这篇文章,接下来是接着上篇内容补充一下该功能的完善,也就是实现SQL字段血缘的解析,这是做Hive血缘或者mysql必须完成的功能,当然实现起来也是比较麻烦的。这里主要讲一下思路和实现的步骤。


一、字段血缘

1.区别字段

字段血缘在于解析树的叶子节点的遍历,这里仍然还是使用递归就行了但是这里需要注意的一点,Function函数也会被遍历到以及表的别名和字段的别名,这两个是需要处理,如果可以的话最好将其提取出来,也有一定的解析必要。我们来看看sqlparse的解析树是如何判定这两个关键字段的:

 

 功能函数还是很好解析的,根据token的parent就可以获取Function字段,但是别名的话就不好处理,和其他字段的解析是一样的。

2.区别标识符序列

这里有两个可以递归的序列,和上次遍历表是不一样的,重点需要考虑的点在于Function和Parenthesis这两个节点都是可以递归的,上次表的遍历需要调整遍历节点,需要将这两个递归节点都要考虑进去。

3.功能函数设定

同样对于字段来说也存在着很多小问题需要处理,如重复字段,以及字段对应表如何关联,去除别名等关键函数需要处理。对于字段的层级和对应表名需要设定一个变量来记录其深度,对于SQL语句来说,如果主题功能是实现建表和插入的话1,肯定第一层语句是存在select选择字段的,那么这一层就可以解析出表的别名,再做去重剔除就好了。

二、字段血缘可视化

实现了字段以及与对应表的关联,作数据可视化也就不难了,拥有pyecharts可以帮我们快速出图。挑选例图需要考虑,对于SQLflow的这种效果还是实现需要开发一定的前端代码:

在看echart的例图中我看到了一个可以适合表达字段血缘的图表,那就是桑葚图。

做成create或者是insert as的话关系为表->表->字段的话正好合适。但是这个有个比较坑的点,就是echart的桑葚图如果字段存在重复的话将不能显示正常的图表。

大体的实现效果如下:

insert into temp.road_check_20220902
select 
m.id as mid,
m.order_id as morder_id,
m.finish_time as mfinish_time,
m.link_id as mlink_id,
m.sid as msid,
m.ctime as mctime,
n.linkid as nlinkid,
n.level as nlevel,
n.ctime as nctime,
n.sids as nsids
from
(
select
        id,
        order_id,
        finish_time,
        link_id,
        sid,
        from_unixtime(
                cast(
                        cast(
                                get_json_object(
                                split(regexp_replace(regexp_replace(frames , '\\[|\\]', ''), '\\}\\,\\{', '\\}\\;\\{'), '\\;')[0]
                                , '$.timestamp'
                                ) as bigint
                        )/ 1000
                 as bigint)
        ,
        'yyyyMMddHHmm')
 as ctime
from
(       
select 	
	id,
        order_id,
        finish_time,
        link_id,
        sid,
	like,
	frames,
	dt
from
        dws_crowdsourcing.cs_order_link_mysql
)
where
        dt = 202208
)m
INNER JOIN 
(
select
linkid ,
level,
from_unixtime(
                cast(
                        cast(
                                gpstime as bigint
                        )/ 1000
                 as bigint)
        ,
        'yyyyMMddHHmm')
 as ctime
,sids
from track_point_traffic_dev.tk_track_traffic_info_offline where 
dt > '2022-08-01' and level > 3
)n on m.link_id = n.linkid and m.ctime = n.ctime
if __name__ == '__main__':
    table_names=[]
    column_names=[]
    function_names=[]
    alias_names=[]
    columns_rank=0
    sql=get_sqlstr('read_sql.txt')
    
    stmt_tuple=analysis_statements(sql)
    for each_stmt in stmt_tuple:
        type_name=get_main_functionsql(each_stmt)
        #get_ASTTree(each_stmt)
        blood_table(each_stmt)
        blood_column(each_stmt)
        column_visus()

 

当然这里还存在三重嵌套,四重嵌套。

但是表的遍历不会存在问题,那么字段的提取通过select提取出的列表也存在多个列表,这里仍然需要考虑。


点关注,防走丢,如有纰漏之处,请留言指教,非常感谢

以上就是本期全部内容。我是fanstuck ,有问题大家随时留言讨论 ,我们下期见

有关基于Python-sqlparse的SQL字段血缘追踪解析实现的更多相关文章

  1. Ruby 解析字符串 - 2

    我有一个字符串input="maybe(thisis|thatwas)some((nice|ugly)(day|night)|(strange(weather|time)))"Ruby中解析该字符串的最佳方法是什么?我的意思是脚本应该能够像这样构建句子:maybethisissomeuglynightmaybethatwassomenicenightmaybethiswassomestrangetime等等,你明白了......我应该一个字符一个字符地读取字符串并构建一个带有堆栈的状态机来存储括号值以供以后计算,还是有更好的方法?也许为此目的准备了一个开箱即用的库?

  2. python - 如何使用 Ruby 或 Python 创建一系列高音调和低音调的蜂鸣声? - 2

    关闭。这个问题是opinion-based.它目前不接受答案。想要改进这个问题?更新问题,以便editingthispost可以用事实和引用来回答它.关闭4年前。Improvethisquestion我想在固定时间创建一系列低音和高音调的哔哔声。例如:在150毫秒时发出高音调的蜂鸣声在151毫秒时发出低音调的蜂鸣声200毫秒时发出低音调的蜂鸣声250毫秒的高音调蜂鸣声有没有办法在Ruby或Python中做到这一点?我真的不在乎输出编码是什么(.wav、.mp3、.ogg等等),但我确实想创建一个输出文件。

  3. ruby - 解析 RDFa、微数据等的最佳方式是什么,使用统一的模式/词汇(例如 schema.org)存储和显示信息 - 2

    我主要使用Ruby来执行此操作,但到目前为止我的攻击计划如下:使用gemsrdf、rdf-rdfa和rdf-microdata或mida来解析给定任何URI的数据。我认为最好映射到像schema.org这样的统一模式,例如使用这个yaml文件,它试图描述数据词汇表和opengraph到schema.org之间的转换:#SchemaXtoschema.orgconversion#data-vocabularyDV:name:namestreet-address:streetAddressregion:addressRegionlocality:addressLocalityphoto:i

  4. ruby - 用逗号、双引号和编码解析 csv - 2

    我正在使用ruby​​1.9解析以下带有MacRoman字符的csv文件#encoding:ISO-8859-1#csv_parse.csvName,main-dialogue"Marceu","Giveittohimóhe,hiswife."我做了以下解析。require'csv'input_string=File.read("../csv_parse.rb").force_encoding("ISO-8859-1").encode("UTF-8")#=>"Name,main-dialogue\r\n\"Marceu\",\"Giveittohim\x97he,hiswife.\"\

  5. ruby-on-rails - 如何验证非模型(甚至非对象)字段 - 2

    我有一个表单,其中有很多字段取自数组(而不是模型或对象)。我如何验证这些字段的存在?solve_problem_pathdo|f|%>... 最佳答案 创建一个简单的类来包装请求参数并使用ActiveModel::Validations。#definedsomewhere,atthesimplest:require'ostruct'classSolvetrue#youcouldevencheckthesolutionwithavalidatorvalidatedoerrors.add(:base,"WRONG!!!")unlesss

  6. ruby-on-rails - form_for 中不在模型中的自定义字段 - 2

    我想向我的Controller传递一个参数,它是一个简单的复选框,但我不知道如何在模型的form_for中引入它,这是我的观点:{:id=>'go_finance'}do|f|%>Transferirde:para:Entrada:"input",:placeholder=>"Quantofoiganho?"%>Saída:"output",:placeholder=>"Quantofoigasto?"%>Nota:我想做一个额外的复选框,但我该怎么做,模型中没有一个对象,而是一个要检查的对象,以便在Controller中创建一个ifelse,如果没有检查,请帮助我,非常感谢,谢谢

  7. ruby - 如何根据特征实现 FactoryGirl 的条件行为 - 2

    我有一个用户工厂。我希望默认情况下确认用户。但是鉴于unconfirmed特征,我不希望它们被确认。虽然我有一个基于实现细节而不是抽象的工作实现,但我想知道如何正确地做到这一点。factory:userdoafter(:create)do|user,evaluator|#unwantedimplementationdetailshereunlessFactoryGirl.factories[:user].defined_traits.map(&:name).include?(:unconfirmed)user.confirm!endendtrait:unconfirmeddoenden

  8. ruby-on-rails - 在 Rails 和 ActiveRecord 中查询时忽略某些字段 - 2

    我知道我可以指定某些字段来使用pluck查询数据库。ids=Item.where('due_at但是我想知道,是否有一种方法可以指定我想避免从数据库查询的某些字段。某种反拔?posts=Post.where(published:true).do_not_lookup(:enormous_field) 最佳答案 Model#attribute_names应该返回列/属性数组。您可以排除其中一些并传递给pluck或select方法。像这样:posts=Post.where(published:true).select(Post.attr

  9. ruby-on-rails - 我更新了 ruby​​ gems,现在到处都收到解析树错误和弃用警告! - 2

    简而言之错误:NOTE:Gem::SourceIndex#add_specisdeprecated,useSpecification.add_spec.Itwillberemovedonorafter2011-11-01.Gem::SourceIndex#add_speccalledfrom/opt/local/lib/ruby/site_ruby/1.8/rubygems/source_index.rb:91./opt/local/lib/ruby/gems/1.8/gems/rails-2.3.8/lib/rails/gem_dependency.rb:275:in`==':und

  10. Python 相当于 Perl/Ruby ||= - 2

    这个问题在这里已经有了答案:关闭10年前。PossibleDuplicate:Pythonconditionalassignmentoperator对于这样一个简单的问题表示歉意,但是谷歌搜索||=并不是很有帮助;)Python中是否有与Ruby和Perl中的||=语句等效的语句?例如:foo="hey"foo||="what"#assignfooifit'sundefined#fooisstill"hey"bar||="yeah"#baris"yeah"另外,类似这样的东西的通用术语是什么?条件分配是我的第一个猜测,但Wikipediapage跟我想的不太一样。

随机推荐