C#实现SQL Server数据血缘关系生成程序
要在现有的C#程序中添加功能,输出SQL Server数据血缘关系的三张表到Excel文件,我们需要进行以下几个步骤:
分析存储过程、视图和函数中的引用关系,构建数据血缘关系。
按依赖性从小到大排序表的顺序。
找出对应生成表的数据的存储过程。
将结果输出到Excel文件。
以下是完整的代码实现:
using Microsoft.SqlServer.TransactSql.ScriptDom;
using OfficeOpenXml;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text.RegularExpressions;class Program
{static void Main(){string directoryPath = @"<搜索的目录路径>";var dataRelations = new Dictionary<string, List<string>>();var tableProcedures = new Dictionary<string, List<string>>();var allTablesAndViews = new HashSet<string>();ProcessSqlFiles(directoryPath, dataRelations, tableProcedures, allTablesAndViews);var sortedTables = SortTablesByDependency(dataRelations, allTablesAndViews);WriteToExcel(dataRelations, sortedTables, tableProcedures);}static void ProcessSqlFiles(string directoryPath, Dictionary<string, List<string>> dataRelations, Dictionary<string, List<string>> tableProcedures, HashSet<string> allTablesAndViews){foreach (string filePath in Directory.EnumerateFiles(directoryPath, "*.sql", SearchOption.AllDirectories)){Console.WriteLine($"Processing file: {filePath}");string sqlContent = File.ReadAllText(filePath);ProcessSqlContent(sqlContent, dataRelations, tableProcedures, allTablesAndViews);CheckCreateStatements(sqlContent, tableProcedures);}}static void ProcessSqlContent(string sqlContent, Dictionary<string, List<string>> dataRelations, Dictionary<string, List<string>> tableProcedures, HashSet<string> allTablesAndViews){TSql150Parser parser = new TSql150Parser(false);IList<ParseError> errors;TSqlFragment fragment = parser.Parse(new StringReader(sqlContent), out errors);if (errors.Count == 0){var referenceVisitor = new ReferenceVisitor(dataRelations, allTablesAndViews);fragment.Accept(referenceVisitor);}else{foreach (var error in errors){Console.WriteLine($"Parse error: {error.Message}");}}}static void CheckCreateStatements(string sqlContent, Dictionary<string, List<string>> tableProcedures){// 匹配创建视图的语句MatchCollection viewMatches = Regex.Matches(sqlContent, @"CREATE\s+VIEW\s+([^\s(]+)", RegexOptions.IgnoreCase);foreach (Match match in viewMatches){Console.WriteLine($"View: {match.Groups[1].Value}");}// 匹配创建存储过程的语句MatchCollection sprocMatches = Regex.Matches(sqlContent, @"CREATE\s+PROC(?:EDURE)?\s+([^\s(]+)", RegexOptions.IgnoreCase);foreach (Match match in sprocMatches){Console.WriteLine($"Stored Procedure: {match.Groups[1].Value}");tableProcedures[match.Groups[1].Value] = new List<string>();}// 匹配创建函数的语句MatchCollection functionMatches = Regex.Matches(sqlContent, @"CREATE\s+(?:FUNCTION|AGGREGATE)\s+([^\s(]+)", RegexOptions.IgnoreCase);foreach (Match match in functionMatches){Console.WriteLine($"User Defined Function: {match.Groups[1].Value}");}}static List<string> SortTablesByDependency(Dictionary<string, List<string>> dataRelations, HashSet<string> allTablesAndViews){var sorted = new List<string>();var visited = new HashSet<string>();foreach (var table in allTablesAndViews){TopologicalSort(table, dataRelations, sorted, visited);}return sorted;}static void TopologicalSort(string node, Dictionary<string, List<string>> dataRelations, List<string> sorted, HashSet<string> visited){if (visited.Contains(node)) return;visited.Add(node);if (dataRelations.ContainsKey(node)){foreach (var child in dataRelations[node]){TopologicalSort(child, dataRelations, sorted, visited);}}sorted.Insert(0, node);}static void WriteToExcel(Dictionary<string, List<string>> dataRelations, List<string> sortedTables, Dictionary<string, List<string>> tableProcedures){using (var package = new ExcelPackage()){var worksheet1 = package.Workbook.Worksheets.Add("Data Relations");worksheet1.Cells[1, 1].Value = "Table/View Name";worksheet1.Cells[1, 2].Value = "Generation Path";int row = 2;foreach (var table in sortedTables){worksheet1.Cells[row, 1].Value = table;worksheet1.Cells[row, 2].Value = GetGenerationPath(table, dataRelations);row++;}var worksheet2 = package.Workbook.Worksheets.Add("Sorted Tables");worksheet2.Cells[1, 1].Value = "Table/View Name";for (int i = 0; i < sortedTables.Count; i++){worksheet2.Cells[i + 2, 1].Value = sortedTables[i];}var worksheet3 = package.Workbook.Worksheets.Add("Table - Procedure Mapping");worksheet3.Cells[1, 1].Value = "Table/View Name";worksheet3.Cells[1, 2].Value = "Stored Procedures";row = 2;foreach (var table in sortedTables){worksheet3.Cells[row, 1].Value = table;worksheet3.Cells[row, 2].Value = string.Join(", ", tableProcedures.GetValueOrDefault(table, new List<string>()));row++;}FileInfo file = new FileInfo("DataBloodline.xlsx");package.SaveAs(file);}}static string GetGenerationPath(string table, Dictionary<string, List<string>> dataRelations){if (!dataRelations.ContainsKey(table)) return table;return table + "->" + string.Join("->", dataRelations[table].Select(t => GetGenerationPath(t, dataRelations)));}
}class ReferenceVisitor : TSqlFragmentVisitor
{private readonly Dictionary<string, List<string>> dataRelations;private readonly HashSet<string> allTablesAndViews;public ReferenceVisitor(Dictionary<string, List<string>> dataRelations, HashSet<string> allTablesAndViews){this.dataRelations = dataRelations;this.allTablesAndViews = allTablesAndViews;}public override void Visit(SelectQuerySpecification node){VisitTableReferences(node.FromClause);}public override void Visit(InsertStatement node){AddReference(node.TableReference);}public override void Visit(UpdateStatement node){AddReference(node.TableReference);}public override void Visit(DeleteStatement node){AddReference(node.TableReference);}public override void Visit(ViewDefinition node){AddReference(node.SchemaObjectName);}private void VisitTableReferences(FromClause fromClause){if (fromClause!= null){foreach (var tableReference in fromClause.TableReferences){AddReference(tableReference);}}}private void AddReference(TSqlFragment fragment){if (fragment is TableReference tableReference){var name = tableReference.SchemaObject.BaseIdentifier.Value;AddInfo(name);}else if (fragment is SchemaObjectName schemaObjectName){var name = schemaObjectName.BaseIdentifier.Value;AddInfo(name);}}private void AddInfo(string name){allTablesAndViews.Add(name);if (!dataRelations.ContainsKey(name)){dataRelations[name] = new List<string>();}}
}
代码说明:
Main方法:初始化变量并调用 ProcessSqlFiles 方法,最后调用 WriteToExcel 方法将结果输出到Excel文件。
ProcessSqlFiles方法:遍历指定目录及其子目录下的所有 .sql 文件,并对每个文件的内容执行 ProcessSqlContent 和 CheckCreateStatements 方法。
ProcessSqlContent方法:使用 Microsoft.SqlServer.TransactSql.ScriptDom 库解析SQL内容,获取引用关系。
CheckCreateStatements方法:使用正则表达式匹配SQL内容中的创建视图、存储过程和函数的语句,并更新 tableProcedures 字典。
SortTablesByDependency方法:使用拓扑排序按依赖性从小到大排序表的顺序。
WriteToExcel方法:使用EPPlus库将数据血缘关系的三张表输出到Excel文件。
ReferenceVisitor类:继承自 TSqlFragmentVisitor ,用于收集SQL语句中的表和视图引用关系。
请确保你已经安装了EPPlus库,可以通过NuGet安装:
Install-Package EPPlus
相关文章:
C#实现SQL Server数据血缘关系生成程序
要在现有的C#程序中添加功能,输出SQL Server数据血缘关系的三张表到Excel文件,我们需要进行以下几个步骤: 分析存储过程、视图和函数中的引用关系,构建数据血缘关系。 按依赖性从小到大排序表的顺序。 找出对应生成表的数据的存储…...
HBuilderX构建Vue项目
版权声明 本文原创作者:谷哥的小弟作者博客地址:http://blog.csdn.net/lfdfhl HBuilderX概述 HBuilderX是一款专为开发者设计的高效开发工具,致力于提升开发者的编码效率和体验。HBuilderX既适合追求极致效率的极客,也适合希望简…...
基于微信小程序的英语学习交流平台设计与实现(LW+源码+讲解)
专注于大学生项目实战开发,讲解,毕业答疑辅导,欢迎高校老师/同行前辈交流合作✌。 技术范围:SpringBoot、Vue、SSM、HLMT、小程序、Jsp、PHP、Nodejs、Python、爬虫、数据可视化、安卓app、大数据、物联网、机器学习等设计与开发。 主要内容:…...
使用 Confluent Cloud 的 Elasticsearch Connector 部署 Elastic Agent
作者:来自 Elastic Nima Rezainia Confluent Cloud 用户现在可以使用更新后的 Elasticsearch Sink Connector 与 Elastic Agent 和 Elastic Integrations 来实现完全托管且高度可扩展的数据提取架构。 Elastic 和 Confluent 是关键的技术合作伙伴,我们很…...
JDK17 HashMap
HashMap ArrayList用动态数组存放元素,而HashMap用动态数组(桶)存储键值对。 如果两个键值对映射到桶同一个索引,则称为散列冲突。HashMap采用拉链法解决冲突,即桶中每个索引指向一个链表或者红黑树,多个键…...
算法随笔_23: 通过删除字母匹配到字典里最长单词
上一篇:算法随笔_22:数组中的k-diff对-CSDN博客 题目描述如下: 给你一个字符串 s 和一个字符串数组 dictionary ,找出并返回 dictionary 中最长的字符串,该字符串可以通过删除 s 中的某些字符得到。 如果答案不止一个,返回长度最长且字母序…...
ansible自动化运维实战--通过role远程部署nginx并配置(8)
文章目录 1、准备工作2、创建角色结构3、编写任务4、准备配置文件(金甲模板)5、编写变量6、编写处理程序7、编写剧本8、执行剧本Playbook9、验证-游览器访问每台主机的nginx页面 在 Ansible 中,使用角色(Role)来远程部…...
Python网络自动化运维---用户交互模块
文章目录 目录 文章目录 前言 实验环境准备 一.input函数 代码分段解析 二.getpass模块 前言 在前面的SSH模块章节中,我们都是将提供SSH服务的设备的账户/密码直接写入到python代码中,这样很容易导致账户/密码泄露,而使用Python中的用户交…...
计算机的错误计算(二百二十二)
摘要 利用大模型化简计算 实验表明,虽然结果正确,但是,大模型既绕了弯路,又有数值计算错误。 与前面相同,再利用同一个算式看看另外一个大模型的化简与计算能力。 例1. 化简计算摘要中算式。 下面是与一个大模型的…...
音频 PCM 格式 - raw data
文章目录 raw 音频格式:PCM其他音频格式:mp31. 无损压缩音频(类比 PNG 图像)2. 有损压缩音频(类比 JPEG 图像) 试了一下科大讯飞的音频识别云 api,踩了点坑 与本文无关:讯飞的 api 使…...
mybatis(78/134)
前天学了很多,关于java的反射机制,其实跳过了new对象,然后底层生成了字节码,创建了对应的编码。手搓了一遍源码,还是比较复杂的。 <?xml version"1.0" encoding"UTF-8" ?> <!DOCTYPE …...
连接 OpenAI 模型:基础操作
在这一部分中,我们将介绍如何连接 OpenAI 模型,设置 API 密钥,并使用 Spring AI 的 ChatClient 与 OpenAI 模型进行简单的对话。Spring AI 为集成 OpenAI 模型提供了方便的工具,使得开发者能够更轻松地与 GPT 系列模型进行交互。 …...
数据分箱 baggingboosting onehot独热编码 woe编码 sklearn的ensemble(集成学习)
目录 数据分箱就是将连续变量离散化。 bagging&boosting onehot独热编码 独热编码的结果如下: woe编码 WOE编码的基本原理 步骤一:计算WOE 步骤二:应用WOE WOE编码的优点 示例 数据示例 步骤一:计算每个类别的违约…...
企业微信开发010_使用WxJava企业微信开发框架_封装第三方应用企业微信开发003_并且实现多企业授权访问---企业微信开发012
继续来看吧,上一节,已经把config部分,代码都拿过来了: 并且把企业微信第三方应用开发部分,对应的config的配置,mutiltp 代码拿过来了,并且把yml中的配置也给出了. 然后,这里说一下config中的内容,到时候自己看也可以看懂 其实就是封装了,当系统启动,加载企微模块,这个时候,会…...
Office2021下载与安装保姆级教程【Office Tool Plus】
Office Tool Plus安装Office2021 下载Office Tool Plus安装OfficeⅠ. 清除旧版本Ⅱ. 配置安装参数Ⅲ. 安装许可证Ⅳ. 激发(JH)Office 本文介绍使用Office Tool Plus工具下载、安装、部署Office 2021全过程。 下载Office Tool Plus OfficeToolPlus是一个…...
salesforce公式字段 ISBLANK 函数和 <> NULL的区别
在 Salesforce 公式字段中,ISBLANK 函数和 <> NULL 的作用都可以用来检查字段是否有值,但它们的行为有一些显著的区别。以下是它们的详细对比和适用场景: 1. 基本区别 功能ISBLANK<> NULL主要作用检查字段是否为空(适…...
Unity在WebGL中拍照和录视频
原工程地址https://github.com/eangulee/UnityWebGLRecoder Unity版本2018.3.6f1,有点年久失修了 https://github.com/xue-fei/Unity.WebGLRecorder 修改jslib适配了Unity2021 效果图 录制的视频 Unity在WebGL中拍照和录视频...
AIGC时代下的Vue组件开发深度探索
文章目录 一、AIGC时代对Vue组件开发的深远影响二、Vue组件开发基础与最佳实践三、AIGC技术在Vue组件开发中的具体应用四、结论与展望 随着人工智能技术的飞速发展,AIGC(人工智能生成内容)时代已经悄然来临。在这个时代背景下,软件…...
【外文原版书阅读】《机器学习前置知识》1.线性代数的重要性,初识向量以及向量加法
目录 编辑 编辑 1.Chapter 2 Why Linear Algebra? 2.Chapter 3 What Is a Vector? 个人主页:Icomi 大家好,我是Icomi,本专栏是我阅读外文原版书《Before Machine Learning》对于文章中我认为能够增进线性代数与机器学习之间的理解的…...
Kafka运维宝典 (三)- Kafka 最大连接数超出限制问题、连接超时问题、消费者消费时间超过限制问题详细介绍
Kafka运维宝典 (三) 文章目录 Kafka运维宝典 (三)一、Kafka Broker 配置中的最大连接数超出限制问题1. 错误原因2. 相关 Kafka 配置参数2.1 connections.max2.2 max.connections.per.ip2.3 num.network.threads2.4 connections.ma…...
SpringBoot开发(二)Spring Boot项目构建、Bootstrap基础知识
1. Spring Boot项目构建 1.1. 简介 基于官方网站https://start.spring.io进行项目的创建. 1.1.1. 简介 Spring Boot是基于Spring4框架开发的全新框架,设计目的是简化搭建及开发过程,并不是对Spring功能上的增强,而是提供了一种快速使用Spr…...
【FISCO BCOS】二十四、通过Java SDK对FISCO BCOS进行压力测试
Java SDK Demo是基于Java SDK的基准测试集合,能够对FISCO BCOS节点进行压力测试。Java SDK Demo提供有合约编译功能,能够将Solidity合约文件转换成Java合约文件,此外还提供了针对转账合约、CRUD合约以及AMOP功能的压力测试示例程序。本篇我们来讲讲使用java SDK压力测试的操…...
【PyTorch】4.张量拼接操作
个人主页:Icomi 在深度学习蓬勃发展的当下,PyTorch 是不可或缺的工具。它作为强大的深度学习框架,为构建和训练神经网络提供了高效且灵活的平台。神经网络作为人工智能的核心技术,能够处理复杂的数据模式。通过 PyTorch࿰…...
新电脑安装系统找不到硬盘原因和解决方法来了
有不少网友反馈新电脑采用官方u盘方式装win10或win100出现找不到硬盘是怎么回事?后来研究半天发现是bios中开启了rst(vmd)模式。如果关闭rst模式肯定是可以安装的,但这会影响硬盘性能,有没有办法解决开启rst模式的情况安装win10或win11呢&…...
Python3 【高阶函数】水平考试:30道精选试题和答案
Python3 【高阶函数】水平考试:30道精选试题和答案 试卷说明 本试卷包含:选择题:15 道、填空题:10 道和 编程题:5 道,总分 100 分。每道题后附有答案和解析。 高阶函数测试试卷 满分:100 分 …...
「 机器人 」仿生扑翼飞行器中的“被动旋转机制”概述
前言 在仿生扑翼飞行器的机翼设计中,模仿昆虫翼的被动旋转机制是一项关键技术。其核心思想在于:机翼旋转角度(攻角)并非完全通过主动伺服来控制,而是利用空气动力和惯性力的作用,自然地实现被动调节。以下对这种设计的背景、原理与优势进行详细说明。 1. 背景:昆虫的被动…...
Android GLSurfaceView 覆盖其它控件问题 (RK平台)
平台 涉及主控: RK3566 Android: 11/13 问题 在使用GLSurfaceView播放视频的过程中, 增加了一个播放控制面板, 覆盖在视频上方. 默认隐藏setVisibility(View.INVISIBLE);点击屏幕再显示出来. 然而, 在RK3566上这个简单的功能却无法正常工作. 通过缩小视频窗口可以看到, 实际…...
【C++】类和对象(五)
1、初始化列表 作用:C提供了初始化列表语法,用来初始化属性。 语法: 构造函数():属性1(值1),属性2(值2)...{}示例: #include<i…...
在win11下搭建ios开发环境
就是安装VMware,然后安装mac虚拟机。 主要参考了这一篇:windows上安装macOS系统虚拟机_windows安装macos虚拟机-CSDN博客 还参考了这一篇:【保姆级别教程】VMware虚拟机安装Mac OS15苹果系统附带【VMware TooLS安装】【解锁虚拟机】和【Mac…...
Maven的下载安装配置
maven的下载安装配置 maven是什么 Maven 是一个用于 Java 平台的 自动化构建工具,由 Apache 组织提供。它不仅可以用作包管理,还支持项目的开发、打包、测试及部署等一系列行为 Maven的核心功能 项目构建生命周期管理:Maven定义了项目构建…...
