解析 SQL Server 查询而不针对数据库连接执行查询 [重复]

Posted

技术标签:

【中文标题】解析 SQL Server 查询而不针对数据库连接执行查询 [重复]【英文标题】:Parsing a SQL Server query without executing the query against a database connection [duplicate] 【发布时间】:2014-10-03 16:21:40 【问题描述】:

这里有点难过。我面前的任务是获取一个存储在字符串中的 SQL 查询(假设它现在是一个有效的查询);将“选择列表”存储在字符串数组中,每个数组元素与选择列表项相关;最后将“from 子句”存储在它自己的字符串变量中。我觉得练习是编写自己的 SQL 查询解析器,但我不知道 SQL Server 是如何解析查询的。非常感谢任何可以提供帮助的资源方向。

我已经能够使用蛮力方法解决问题,我执行以下操作:

1 - 通过启动一个循环来查找 from 子句,该循环查找单词“from”的后续实例,直到索引位置之后的所有内容都可以使用“select *”选择列表

private string GetFromClause(string selectstatement,string connectionString)

    string teststatement = selectstatement;
    int startindex = GetFirstFromIndex(teststatement);
    while (startindex != -1)
     
        teststatement=teststatement.Substring(startindex);
        if (DoesSelectWork(string.Format("select * 0", teststatement)
                                                    , connectionString))
            return teststatement;
        else
            startindex = GetNextFromIndex(teststatement);

     
    throw new ReportException("Could not find From Clause");

2- 从传递的查询中删除现在找到的“from 子句”;使用 .split(',') 将剩余的字符串放在一个数组中。现在遍历数组并使用找到的“from 子句”测试每个数组元素。如果测试通过,我们就有一个有效的选择列表项;如果不是,我们想将此元素与下一个数组元素组合,并继续这样做直到测试通过(以处理将逗号引入选择列表语法的转换语句等)

private string[] GetSelectFields(string query, 
                                string fromclause,
                                string connectionString)

    int index = query.IndexOf(fromclause);
    string fromless = (index < 0)
        ? query
        : query.Remove(index, fromclause.Length);
    fromless = fromless.Substring(fromless.IndexOf("SELECT") + "SELECT".Length);
    List<string> finalselect = new List<string>();
    string[] selectFields = fromless.Split(',');
    index = 0;            
    string currentString = string.Empty;
    while (index<selectFields.Length)
    
        currentString += selectFields[index];
        if (DoesSelectWork(string.Format("select 0 1"
                , currentString, fromclause), connectionString))
        
            finalselect.Add(currentString);
            currentString = string.Empty;
        
        else 
            currentString += ",";
        
        index++;
    
    return finalselect.ToArray();

【问题讨论】:

听起来你在测试字符串 is 对我来说是否是一个有效的查询? 这里使用存储过程有什么问题?为什么不使用存储过程并进行整个字符串查询? ***.com/questions/3276035/… 【参考方案1】:

作为一般规则,您无法使用简单的搜索方法解析 SQL,规则太复杂了。你需要一个完整的词法分析器和语法。但是从 SQL Server 2012 开始,您有了 Transact-SQL 语言服务选项,这是 Visual Studio 等工具用来解析没有后端服务器的 T-SQL 的工具。您可以通过 C# 从 C# 中利用它 Microsoft.SqlServer.Management.SqlParser.Parser.Parse().

【讨论】:

我认为@JhonAlx 链接的TSqlParserScriptDom 实际上是一个更好的选择。更好的记录。 它实际上是Microsoft.SqlServer.Management.SqlParser.Parser.Parser.Parse(),其中Microsoft.SqlServer.Management.SqlParser.Parser 是命名空间,Parser 是(静态)类【参考方案2】:

如果您想在不使用数据库的情况下验证 SQL 语法,TSql100Parser 类将非常适合这种情况。

免责声明,代码从这里的帖子中借用Code to validate SQL Scripts

虽然使用起来非常简单。如果返回null,则解析没有错误。

using Microsoft.Data.Schema.ScriptDom;
using Microsoft.Data.Schema.ScriptDom.Sql;

public class SqlParser

        public List<string> Parse(string sql)
        
            TSql100Parser parser = new TSql100Parser(false);
            IScriptFragment fragment;
            IList<ParseError> errors;
            fragment = parser.Parse(new StringReader(sql), out errors);
            if (errors != null && errors.Count > 0)
            
                List<string> errorList = new List<string>();
                foreach (var error in errors)
                
                    errorList.Add(error.Message);
                
                return errorList;
            
            return null;
        

【讨论】:

以上是关于解析 SQL Server 查询而不针对数据库连接执行查询 [重复]的主要内容,如果未能解决你的问题,请参考以下文章

SQL Server之索引解析

sqlserver中游标循环中只更新当前行的方法

SQL Server执行计划

SQL Server调优系列基础篇(常用运算符总结——三种物理连接方式剖析)

调整查询以解析 SQL Server 2014 上的 XML 数据

全面解析SQL SERVER 的左右内连接