百度360必应搜狗淘宝本站头条
当前位置:网站首页 > 技术分析 > 正文

c# 怎样能写个sql的解析器 c#读取sql server

liebian365 2024-10-28 17:16 25 浏览 0 评论

前言

阅读本文需要有一定正则表达式基础 正则表达式基础教程 ,和编译原理的基础。有使用过VUE的伙伴可能知道vue是自定了模版解析编译器的,vue用的是标准的AST语法树统计,如果对语法树不了了解的请查看 什么是AST抽像语法树

本示例介绍的是参考编译原理 词法分析->语法分析->构建AST语法树->解析成目标sql 的流程来实现

示例

sqlserver 的一条查询语句

select  a.UniqueCode,a.BarCode,a.CategoryId from GD_UniqueCodeInfo as a

假如我们要将以上代码进行格式化成以下方式

select  [a].[UniqueCode],[a].[BarCode],[a].[CategoryId] from [GD_UniqueCodeInfo] as [a]

分析

首先我们来分析一下这个语句有什么特点。

  1. 找关键词
    这个sql语法有三个关键词如
    select ,from,as
  2. 找结构
    有字段信息
    a.UniqueCode,a.BarCode,a.CategoryId,有表名信息GD_UniqueCodeInfo 还有 重命名的表信息a 这些信息可能符合命名规范可能有些不符合,那么在解析时都要进行检测出来
  3. 标识符
    在生成的目标sql语句中有[] 这个的作用主要是万一字段名称出现与关键词有相同的字段名称能进行正常识别

开始

首先我们先创建两个c#解析正则表达式的方法

这个方法就是可以将正则表达式中的匹配数据提出来返回一个字典数据

  public static Dictionary<string, string> RegexGrp(string regex,string text)
  {
        Regex _regex = new Regex(regex, RegexOptions.IgnoreCase | RegexOptions.Multiline);
        Dictionary<string, string> _dic = new Dictionary<string, string>();
        Match _match = _regex.Match(text);
        while (_match.Success)
        {
            foreach (string name in _regex.GetGroupNames())
            {
                if(!_dic.ContainsKey(name))
                    _dic.Add(name, _match.Groups[_regex.GroupNumberFromName(name)].Value);
            }
            _match = _match.NextMatch();
        }
        return _dic;
  }

检测正则表达工是否正确匹配

public static bool RegexMatch(string regex, string text)
        {
            Regex _regex = new Regex(regex, RegexOptions.IgnoreCase | RegexOptions.Multiline);
            Match _match = _regex.Match(text);
            return _match.Success;
        }

第一步 先检测这个sql语句是否是一个查询语句

正则代码:^\s*(?<cmd>select)\s+(?<field>[\w\s\S]+(?=\bfrom\b))(?:\bfrom\b)(?<from>(?:[\s]+)(?<flag>[\#]{1,2}|[\@]{1})?(?<tab>[\w]+)\s*[\s\w\S]*)

那么我们来验证下
通过把要解析的SQL语句放入测试工具中运行

在右下方的区域通过正则匹配已经把该语句结构已经拆解出来了
cmd:
select
field:a.UniqueCode,a.BarCode,a.CategoryId
tab:GD_UniqueCodeInfo

一下就把SQL语句结构化出来了,有匹配结果说明是一个正常的sql语句

第二步 通过代码获取结构信息

  string sql="select  a.UniqueCode,a.BarCode,a.CategoryId from GD_UniqueCodeInfo as a";
  Dictionary<string, string> dic =RegexGrp(@"^\s*(?<cmd>select)\s+(?<field>[\w\s\S]+(?=\bfrom\b))(?:\bfrom\b)(?<from>(?:[\s]+)(?<flag>[\#]{1,2}|[\@]{1})?(?<tab>[\w]+)\s*[\s\w\S]*)",sql);

  if(dic.ConstainsKey("cmd"))
  {
    // 说明匹配成功
    Console.Write(dic["cmd"]);
    
  }


拆解select 后要把select 替换为空剩余的sql 为a.UniqueCode,a.BarCode,a.CategoryId from GD_UniqueCodeInfo as a

第三步 拆解字段

正则表达式:^\s*(?<field>[\w\s\S]*?(?=\bfrom\b))
两人通过测试工具测试一下

那么就可以通过代码获取出来

  string sql="a.UniqueCode,a.BarCode,a.CategoryId from GD_UniqueCodeInfo as a";
  Dictionary<string, string> dic =RegexGrp(@"^\s*(?<field>[\w\s\S]*?(?=\bfrom\b))",sql);
  if (dic.ContainsKey("field"))
  {
    //说明匹配成功 
  }

字段是有多个的 还要单独拆解成一个一个的字段,拆解字段的这个就不详细描述了,可以继续用正则表达式也可以用Split(',') 进行分拆

var _field=dic["field"];
var fields=_field.Split(',')

拆解完字段后 剩余的sql:from GD_UniqueCodeInfo as a

拆解from

正则表达式:^\s*(?:\bfrom\b)(?<from>(?:[\s]+)(?<table>(?:[\s]*)(?<flag>[\#]{1,2}|[\@]{1})?(?<tab>[\w]+))\s*(?:\bas\b\s*(?<asname>[\w]+))?\s*)
通过该正则表达式可以拆解出 通过 as 重命名的表
下面通过正则表达式工具测试一下

那么通过以下代码来获取

string sql="from GD_UniqueCodeInfo as a";
  Dictionary<string, string> dic =RegexGrp(@"^\s*(?:\bfrom\b)(?<from>(?:[\s]+)(?<table>(?:[\s]*)(?<flag>[\#]{1,2}|[\@]{1})?(?<tab>[\w]+))\s*(?:\bas\b\s*(?<asname>[\w]+))?\s*)",sql);
  if (dic.ContainsKey("tab"))
  {
    //说明匹配成功 
  }

此时 就算通过正则表达式拆解完成,但还需要对它进行结构化

以下是代码截图片段

结果

请查看demo代码:https://gitee.com/dotnetlowcode/hisql/blob/master/HiSql.SqlServerUnitTest/Demo_Query.cs

相关推荐

go语言也可以做gui,go-fltk让你做出c++级别的桌面应用

大家都知道go语言生态并没有什么好的gui开发框架,“能用”的一个手就能数的清,好用的就更是少之又少。今天为大家推荐一个go的gui库go-fltk。它是通过cgo调用了c++的fltk库,性能非常高...

旧电脑的首选系统:TinyCore!体积小+精简+速度极快,你敢安装吗

这几天老毛桃整理了几个微型Linux发行版,准备分享给大家。要知道可供我们日常使用的Linux发行版有很多,但其中的一些发行版经常会被大家忽视。其实这些微型Linux发行版是一种非常强大的创新:在一台...

codeblocks和VS2019下的fltk使用中文

在fltk中用中文有点问题。英文是这样。中文就成这个样子了。我查了查资料,说用UTF-8编码就行了。edit->Fileencoding->UTF-8然后保存文件。看下下边的编码指示确...

FLTK(Fast Light Toolkit)一个轻量级的跨平台Python GUI库

FLTK(FastLightToolkit)是一个轻量级的跨平台GUI库,特别适用于开发需要快速、高效且简单界面的应用程序。本文将介绍Python中的FLTK库,包括其特性、应用场景以及如何通过代...

中科院开源 RISC-V 处理器“香山”流片,已成功运行 Linux

IT之家1月29日消息,去年6月份,中科院大学教授、中科院计算所研究员包云岗,发布了开源高性能RISC-V处理器核心——香山。近日,包云岗在社交平台晒出图片,香山芯片已流片,回片后...

Linux 5.13内核有望合并对苹果M1处理器支持的初步代码

预计Linux5.13将初步支持苹果SiliconM1处理器,不过完整的支持工作可能还需要几年时间才能完全完成。虽然Linux已经可以在苹果SiliconM1上运行,但这需要通过一系列的补丁才能...

Ubuntu系统下COM口测试教程(ubuntu port)

1、在待测试的板上下载minicom,下载minicom有两种方法:方法一:在Ubuntu软件中心里面搜索下载方法二:按“Ctrl+Alt+T”打开终端,打开终端后输入“sudosu”回车;在下...

湖北嵌入式软件工程师培训怎么选,让自己脱颖而出

很多年轻人毕业即失业、面试总是不如意、薪酬不满意、在家躺平。“就业难”该如何应对,参加培训是否能改变自己的职业走向,在湖北,有哪些嵌入式软件工程师培训怎么选值得推荐?粤嵌科技在嵌入式培训领域有十几年经...

新阁上位机开发---10年工程师的Modbus总结

前言我算了一下,今年是我跟Modbus相识的第10年,从最开始的简单应用到协议了解,从协议开发到协议讲解,这个陪伴了10年的协议,它一直没变,变的只是我对它的理解和认识。我一直认为Modbus协议的存...

创建你的第一个可运行的嵌入式Linux系统-5

@ZHangZMo在MicrochipBuildroot中配置QT5选择Graphic配置文件增加QT5的配置修改根文件系统支持QT5修改output/target/etc/profile配置文件...

如何在Linux下给zigbee CC2530实现上位机

0、前言网友提问如下:粉丝提问项目框架汇总下这个网友的问题,其实就是实现一个网关程序,内容分为几块:下位机,通过串口与上位机相连;下位机要能够接收上位机下发的命令,并解析这些命令;下位机能够根据这些命...

Python实现串口助手 - 03串口功能实现

 串口调试助手是最核心的当然是串口数据收发与显示的功能,pzh-py-com借助的是pySerial库实现串口收发功能,今天痞子衡为大家介绍pySerial是如何在pzh-py-com发挥功能的。一、...

为什么选择UART(串口)作为调试接口,而不是I2C、SPI等其他接口

UART(通用异步收发传输器)通常被选作调试接口有以下几个原因:简单性:协议简单:UART的协议非常简单,只需设置波特率、数据位、停止位和校验位就可以进行通信。相比之下,I2C和SPI需要处理更多的通...

同一个类,不同代码,Qt 串口类QSerialPort 与各种外设通讯处理

串口通讯在各种外设通讯中是常见接口,因为各种嵌入式CPU中串口标配,工业控制中如果不够还通过各种串口芯片进行扩展。比如spi接口的W25Q128FV.对于软件而言,因为驱动接口固定,软件也相对好写,因...

嵌入式linux为什么可以通过PC上的串口去执行命令?

1、uboot(负责初始化基本硬bai件,如串口,网卡,usb口等,然du后引导系统zhi运行)2、linux系统(真正的操作系统)3、你的应用程序(基于操作系统的软件应用)当你开发板上电时,u...

取消回复欢迎 发表评论: