Python-sqlparseに基づくSQL表の血統追跡分析の実装

目次

序文

主なタスク

1. データガバナンス

2.血統追跡

3. SQL テーブルの血液

第二に、実現プロセス

1. 対象効果

2. コードの実装

1.機能機能識別

2. SQL 標準フォーマット

 3. AST ツリーを解析する

4. 最終効果:

注意してください、迷子にならないようにしてください。間違いがある場合は、メッセージを残してアドバイスをお願いします。どうもありがとうございました


序文

以前、SQLparse のオープン ソース ライブラリ分析に関する 2 つの記事で、私は Python プログラミングで実現可能な SQL 系統分析を探していたと述べました. JAVA を使用して Hive のソース コードの実践を解析する場合は、後の段階でそれを行う予定です. 、Python で実装できるようにします。最初に完成させてください。主な理由は、HiveSQL の最下層が Java コードであり、それを書き換える方法がまだ Java を回避できないことです。ただ、前回の連載でsqlparseについて触れましたが、実際にはこのライブラリで血液を解析することは不可能ではありませんが、実現できる機能は限られています. 現時点では、私の実験はOKで、より複雑なSQLも可能です.うまく展開できるサービスのレベルに達したと考えられますが、SQLの形式でマッチングすると、完全にマッチングしきれないSQL形式もあるはずです。 、再度確認できます。

これまでの落とし穴の一部は埋められたと考えられますが、現在の開発進捗はSQL表の血縁関係解析まで追跡可能であり、血縁関係を実現するための機能開発が次々と着手される予定です。


主なタスク

まず、プロジェクトの目標を分析しましょう. SQL リネージ分析に関して言えば、これはデータ ガバナンスに偏っています。

1. データガバナンス

データ ガバナンスは、組織内でのデータの使用に関する一連の管理行動です。データから価値を生み出すには、合理的な「ビジネス目標」が必要です。すべてのデータ ガバナンス アクティビティは、実際のビジネス目標に基づいて実行する必要があります。データ標準の確立とデータ品質の向上は、単なる手段であり、目標ではありません。

データガバナンスの本質はデータを管理することであるため、メタデータ管理とマスターデータ管理を強化し、ソースからデータを管理し、メタデータ、品質、セキュリティ、ビジネスロジックなどの関連する属性とデータの情報を補完する必要があります。メタデータによる血縁関係など データの生成、処理、使用を管理するためのデータ駆動型のアプローチ。

データの品質は、データの価値に直接影響し、データ分析の結果とそれに基づいて行う意思決定の品質に直接影響します。データモデルの血統とタスクスケジューリングの一貫性は、構築と管理の統合の鍵であり、データ管理とデータ生産能力の一貫性の欠如の問題を解決するのに役立ち、一貫性のない二重管理による非効率的な管理モデルの出現を回避します。

2.血統追跡

データがビジネス シナリオで使用され、データ エラーが見つかった場合、データ ガバナンス チームはデータ ソースをすばやく見つけてデータ エラーを修正する必要があります。次に、データ ガバナンス チームは、ビジネス チームのデータがどのコア ライブラリに由来するか、およびコア ライブラリのデータがどのデータ ソースに由来するかを知る必要があります。メタデータとデータリソースリストとの対応関係を構築し、メタデータの組み合わせで業務チームが利用するデータ項目を構成することで、データ利用シナリオとデータソースの血縁関係を構築することが実践されています。設立。データ リソース カタログ: データ リソース カタログは、一般に、政府部門間のデータ共有などのデータ共有シナリオで使用されます. データ リソース カタログは、ビジネス シナリオと業界仕様に基づいて作成され、メタデータと基本的なライブラリ テーマに基づいて自動化されます. データアプリケーションと使用。

そのため、SQL を解析し、テーブルのインデックス作成や参照解析を追跡する必要があります。

3. SQL テーブルの血液

次に、最も重要なことは、さまざまなデータベース間のデータ関係についてです.テーブルの構築と挿入および更新操作により、データに特定の変更が発生するため、これらの操作を許可する必要がありますか? ネットで見かけた某企業のプログラマーがライブラリを削除して逃げたり、うっかり間違ったデータを削除してしまい、生産・研究ラ​​インが遅れてしまった、などなど。上記のような事故の発生を防ぐためには、この操作に対する保険の層を持ち、メンバーごとにデータ操作権限を設定する必要があります。このように、提出された SQL ステートメントには、もう 1 つの判断層があります。

第二に、実現プロセス

1. 対象効果

まず第一に、私たちはどのようなフォームを作成する必要があるかを理解する必要があります. その中で、SQLFlow は間違いなく業界の最前線です:

 この写真を初めて見たとき、各フィールドとテーブル間の血統関係を明確に解析できる血統追跡はこのようにすべきだと判断しました。これにより、アウトプットのベンチマークを設定し、これから行うプロジェクトの目標はまさにそれです。

 

2. コードの実装

1.機能機能識別

この関数も実装しなければならない関数なので、このSQLが主に何をするのかを理解する必要があります。INSERTやCREATEであれば血縁関係の解析が必要で、SELECTであれば簡単なSQL解析ができます。sqlparse ソース コードを調べた結果、対応する関数を呼び出すことができます。

sql="select * from table1;insert into table select a,b,c from table2"

if __name__ == '__main__':
    table_names=[]
    #sql=get_sqlstr('read_sql.txt')
    stmt_tuple=analysis_statements(sql)
    for each_stmt in stmt_tuple:
        type_name=get_main_functionsql(each_stmt)
        print(type_name)

出力:

 

 次に、SELECT については、SQL に関係するテーブルをトレースできます。

CREATE と INSERT の場合、血縁関係を行うことができます。

2. SQL 標準フォーマット

着信 SQL の場合、最初にこのステートメントを標準の SQL ステートメント形式に準拠させる必要があります。これにより、送信形式の一貫性と互換性が確保されます。通常、私たちはテキストを通して読みます。したがって、処理のためにテキストを読む必要があります。

原文:

 処理後:

if __name__ == '__main__':
    sql=get_sqlstr('read_sql.txt')
    print(sql)

 3. AST ツリーを解析する

ANTRL であれ SQLPARSE であれ、結果として得られる SQL は、再帰的なバックトラッキングのためにツリーに解析されます。最後に、本番 SQL​​ ツリーを解析する必要があります。

sql="select * from table1;insert into table3 select a,b,c from table2"

if __name__ == '__main__':
    #sql=get_sqlstr('read_sql.txt')
    stmt_tuple=analysis_statements(sql)
    for each_stmt in stmt_tuple:
        table_names=[]
        type_name=get_main_functionsql(each_stmt)
        get_ASTTree(each_stmt)

 

4. 最終効果:

SQL:


select
b.product_name "产品",
count(a.order_id) "订单量",
b.selling_price_max "销售价",
b.gross_profit_rate_max/100 "毛利率",
case when b.business_type =1 then '自营消化' when b.business_type =2 then '服务商消化'  end "消化模式"
from(select 'CRM签单' label,date(d.update_ymd) close_ymd,c.product_name,c.product_id,
    a.order_id,cast(a.recipient_amount as double) amt,d.cost
    from mysql4.dataview_fenxiao.fx_order a
    left join mysql4.dataview_fenxiao.fx_order_task b on a.order_id = b.order_id
    left join mysql7.dataview_trade.ddc_product_info c on cast(c.product_id as varchar) = a.product_ids and c.snapshot_version = 'SELLING'
    inner join (select t1.par_order_id,max(t1.update_ymd) update_ymd,
                sum(case when t4.product2_type = 1 and t5.shop_id is not null then t5.price else t1.order_hosted_price end) cost
               from hive.bdc_dwd.dw_mk_order t1
               left join hive.bdc_dwd.dw_mk_order_status t2 on t1.order_id = t2.order_id and t2.acct_day = substring(cast(DATE_ADD('day',-1,CURRENT_DATE) as varchar),9,2)
               left join mysql7.dataview_trade.mk_order_merchant t3 on t1.order_id = t3.order_id
               left join mysql7.dataview_trade.ddc_product_info t4 on t4.product_id = t3.MERCHANT_ID and t4.snapshot_version = 'SELLING'
               left join mysql4.dataview_scrm.sc_tprc_product_info t5 on t5.product_id = t4.product_id and t5.shop_id = t1.seller_id
               where t1.acct_day = substring(cast(DATE_ADD('day',-1,CURRENT_DATE) as varchar),9,2)
               and t2.valid_state in (100,200) ------有效订单
               and t1.order_mode = 10    --------产品消耗订单
               and t2.complete_state = 1  -----订单已经完成
               group by t1.par_order_id
    ) d on d.par_order_id  = b.task_order_id
    where c.product_type = 0 and date(from_unixtime(a.last_recipient_time)) > date('2016-01-01') and a.payee_type <> 1 -----------已收款
    UNION ALL
    select '企业管家消耗' label,date(c.update_ymd) close_ymd,b.product_name,b.product_id,
    a.task_id,(case when a.yb_price = 0 and b.product2_type = 1 then b.selling_price_min else a.yb_price end) amt,
    (case when a.yb_price = 0 and b.product2_type = 2 then 0 when b.product2_type = 1 and e.shop_id is not null then e.price else c.order_hosted_price end) cost
    from mysql8.dataview_tprc.tprc_task a
    left join mysql7.dataview_trade.ddc_product_info b on a.product_id = b.product_id and b.snapshot_version = 'SELLING'
    inner join hive.bdc_dwd.dw_mk_order c on a.order_id = c.order_id and c.acct_day = substring(cast(DATE_ADD('day',-1,CURRENT_DATE) as varchar),9,2)
    left join hive.bdc_dwd.dw_mk_order_status d on d.order_id = c.order_id and d.acct_day = substring(cast(DATE_ADD('day',-1,CURRENT_DATE) as varchar),9,2)
    left join mysql4.dataview_scrm.sc_tprc_product_info e on e.product_id = b.product_id and e.shop_id = c.seller_id
    where  d.valid_state in (100,200) and d.complete_state = 1  and c.order_mode = 10
    union ALL
    select '交易管理系统' label,date(t6.close_ymd) close_ymd,t4.product_name,t4.product_id,
    t1.order_id,(t1.order_hosted_price-t1.order_refund_price) amt,
    (case when t1.order_mode <> 11 then t7.user_amount when t1.order_mode = 11 and t4.product2_type = 1 and t5.shop_id is not null then t5.price else t8.cost end) cost
    from hive.bdc_dwd.dw_mk_order t1
    left join hive.bdc_dwd.dw_mk_order_business t2 on t1.order_id = t2.order_id and t2.acct_day=substring(cast(DATE_ADD('day',-1,CURRENT_DATE) as varchar),9,2)
    left join mysql7.dataview_trade.mk_order_merchant t3 on t1.order_id = t3.order_id
    left join mysql7.dataview_trade.ddc_product_info t4 on t4.product_id = t3.MERCHANT_ID and t4.snapshot_version = 'SELLING'
    left join mysql4.dataview_scrm.sc_tprc_product_info t5 on t5.product_id = t4.product_id and t5.shop_id = t1.seller_id
    left join hive.bdc_dwd.dw_fact_task_ss_daily t6 on t6.task_id = t2.task_id and t6.acct_time=date_format(date_add('day',-1,current_date),'%Y-%m-%d')
    left join (select a.task_id,sum(a.user_amount) user_amount
               from hive.bdc_dwd.dw_fn_deal_asyn_order a
               where a.is_new=1 and a.service='Trade_Payment' and a.state=1 and a.acct_day=substring(cast(DATE_ADD('day',-1,CURRENT_DATE) as varchar),9,2)
               group by a.task_id)t7 on t7.task_id = t2.task_id          
    left join (select t1.par_order_id,sum(t1.order_hosted_price - t1.order_refund_price) cost
               from hive.bdc_dwd.dw_mk_order t1
               where t1.acct_day = substring(cast(DATE_ADD('day',-1,CURRENT_DATE) as varchar),9,2) and t1.order_type = 1 and t1.order_stype = 4 and t1.order_mode = 12
               group by t1.par_order_id) t8 on t1.order_id = t8.par_order_id
    where t1.acct_day = substring(cast(DATE_ADD('day',-1,CURRENT_DATE) as varchar),9,2)
    and t1.order_type = 1 and t1.order_stype in (4,5) and t1.order_mode <> 12 and t4.product_id is not null and t1.order_hosted_price > 0 and t6.is_deal = 1 and t6.close_ymd >= '2018-12-31'
)a
left join mysql7.dataview_trade.ddc_product_info b on a.product_id = b.product_id and b.snapshot_version = 'SELLING'
where b.product2_type = 1 -------标品
and close_ymd between DATE_ADD('day',-7,CURRENT_DATE)  and DATE_ADD('day',-1,CURRENT_DATE)
GROUP BY b.product_name,
b.selling_price_max,
b.gross_profit_rate_max/100,
b.actrul_supply_num,
case when b.business_type =1 then '自营消化' when b.business_type =2 then '服务商消化'  end
order by count(a.order_id) desc
limit 10
if __name__ == '__main__':
    table_names=[]
    sql=get_sqlstr('read_sql.txt')
    
    stmt_tuple=analysis_statements(sql)
    for each_stmt in stmt_tuple:
        type_name=get_main_functionsql(each_stmt)
        blood_table(each_stmt)
        Tree_visus(table_names,type_name)
        

 

注意してください、迷子にならないようにしてください。間違いがある場合は、メッセージを残してアドバイスをお願いします。どうもありがとうございました

この問題は以上です。ご不明な点がございましたら、お気軽にメッセージを残してください。次号でお会いしましょう

おすすめ

転載: blog.csdn.net/master_hunter/article/details/127387722