代码之家  ›  专栏  ›  技术社区  ›  Opflash

使用TSqlParser

  •  19
  • Opflash  · 技术社区  · 16 年前

    我正在尝试使用microsoft提供的TSql100Parser解析SQL。现在我在使用它的方式上有点困难。此外,缺少文档也无济于事(例子: http://msdn.microsoft.com/en-us/library/microsoft.data.schema.scriptdom.sql.tsql100parser.aspx

    当我通过解析器运行一个简单的SELECT语句时,它返回一个包含SELECT语句的TSqlStatements集合。 问题是,TSqlSelect语句不包含WHERE子句等属性,即使该子句是作为类实现的。 http://msdn.microsoft.com/en-us/library/microsoft.data.schema.scriptdom.sql.whereclause.aspx

    我的测试项目:

    public static void Main(string[] args)
    {
        var parser = new TSql100Parser(false);
    
                IList<ParseError> Errors;
                IScriptFragment result = parser.Parse(
                    new StringReader("Select col from T1 where 1 = 1 group by 1;" +
                        "select col2 from T2;" +
                        "select col1 from tbl1 where id in (select id from tbl);"),
                        out Errors);
    
                var Script = result as TSqlScript;
    
                foreach (var ts in Script.Batches)
                {
                    Console.WriteLine("new batch");
    
                    foreach (var st in ts.Statements)
                    {
                        IterateStatement(st);
                    }
                }
    }
    
    static void IterateStatement(TSqlStatement statement)
    {
                Console.WriteLine("New Statement");
    
                if (statement is SelectStatement)
                {
                    PrintStatement(sstmnt);
                }
    }
    
    4 回复  |  直到 16 年前
        1
  •  25
  •   doza    16 年前

    是的,您正确地使用了解析器。

    正如不信者Damien_所指出的,在SelectStatement中有一个QueryExpression属性,它将是 查询规范 对象作为第三个select语句(带有WHERE子句)。

    这表示查询的“真实”选择位(而您正在查看的外部SelectStatement对象刚刚获得了“WITH”子句(对于CTE)、“for”子句(对于XML)、“ORDER BY”和其他位)

    查询规范 从句 , where子句 ,

    因此,您可以使用以下命令访问WHERE子句:

    ((QuerySpecification)((SelectStatement)statement).QueryExpression).WhereClause
    

    它具有SearchCondition属性等。

        2
  •  5
  •   Damien_The_Unbeliever    16 年前

    快速浏览一下就会发现它包含一个QueryExpression,可能是一个QuerySpecification,它确实附加了Where子句。

        3
  •  5
  •   Andrey Morozov    13 年前

    如果有人来到这里并想知道如何获取select语句的全部元素,下面的代码将对此进行解释:

    QuerySpecification spec = (QuerySpecification)(((SelectStatement)st).QueryExpression);
    StringBuilder sb = new StringBuilder();
    sb.AppendLine("Select Elements");
    foreach (var elm in spec.SelectElements)                            
      sb.Append(((Identifier)((Column)((SelectColumn)elm).Expression).Identifiers[0]).Value);
    
    sb.AppendLine();
    
    sb.AppendLine("From Elements");
    foreach (var elm in spec.FromClauses)
      sb.Append(((SchemaObjectTableSource)elm).SchemaObject.BaseIdentifier.Value);
    sb.AppendLine();
    
    sb.AppendLine("Where Elements");
    BinaryExpression binaryexp = (BinaryExpression)spec.WhereClause.SearchCondition;
    sb.Append("operator is " + binaryexp.BinaryExpressionType);
    if (binaryexp.FirstExpression is Column)
      sb.Append(" First exp is " + ((Identifier)((Column)binaryexp.FirstExpression).Identifiers[0]).Value);
    
    if (binaryexp.SecondExpression is Literal)
      sb.Append(" Second exp is " + ((Literal)binaryexp.SecondExpression).Value);
    
        4
  •  1
  •   edecadoudal    14 年前

    我不得不把SELECT语句分成几部分。我的目标是计算一个查询将返回多少条记录。我的第一个解决方案是构建一个子查询,如

    SELECT COUNT(*) FROM (select id, name from T where cat='A' order by id) as QUERY
    

    问题在于,在本例中,order子句引发错误“order BY子句在视图、内联函数、派生表、子查询和公共表表达式中无效,除非还指定了TOP或FOR XML”

    using Microsoft.Data.Schema.ScriptDom.Sql;
    using Microsoft.Data.Schema.ScriptDom;
    using System.IO;
    ...
    public class SelectParser
    {
        public string Parse(string sqlSelect, out string fields, out string from, out string groupby, out string where, out string having, out string orderby)
        {
            TSql100Parser parser = new TSql100Parser(false);
            TextReader rd = new StringReader(sqlSelect);
            IList<ParseError> errors;
            var fragments = parser.Parse(rd, out errors);
    
            fields = string.Empty;
            from = string.Empty;
            groupby = string.Empty;
            where = string.Empty;
            orderby = string.Empty;
            having = string.Empty;
    
            if (errors.Count > 0)
            {
                var retMessage = string.Empty;
                foreach (var error in errors)
                {
                    retMessage += error.Identifier + " - " + error.Message + " - position: " + error.Offset + "; ";
                }
    
                return retMessage;
            }
    
            try
            {
                // Extract the query assuming it is a SelectStatement
                var query = ((fragments as TSqlScript).Batches[0].Statements[0] as SelectStatement).QueryExpression;
    
                // Constructs the From clause with the optional joins
                from = (query as QuerySpecification).FromClauses[0].GetString();
    
                // Extract the where clause
                where = (query as QuerySpecification).WhereClause.GetString();
    
                // Get the field list
                var fieldList = new List<string>();
                foreach (var f in (query as QuerySpecification).SelectElements)
                    fieldList.Add((f as SelectColumn).GetString());
                fields = string.Join(", ", fieldList.ToArray());
    
                // Get The group by clause
                groupby = (query as QuerySpecification).GroupByClause.GetString();
    
                // Get the having clause of the query
                having = (query as QuerySpecification).HavingClause.GetString();
    
                // Get the order by clause
                orderby = ((fragments as TSqlScript).Batches[0].Statements[0] as SelectStatement).OrderByClause.GetString();
            }
            catch (Exception ex)
            {
                return ex.ToString();
            }
    
            return string.Empty;
        }
    }
    
    
    public static class Extension
    {
        /// <summary>
        /// Get a string representing the SQL source fragment
        /// </summary>
        /// <param name="statement">The SQL Statement to get the string from, can be any derived class</param>
        /// <returns>The SQL that represents the object</returns>
        public static string GetString(this TSqlFragment statement)
        {
            string s = string.Empty;
            if (statement == null) return string.Empty;
    
            for (int i = statement.FirstTokenIndex; i <= statement.LastTokenIndex; i++)
            {
                s += statement.ScriptTokenStream[i].Text;
            }
    
            return s;
        }
    }
    

    要简单地使用这个类:

    string fields, from, groupby, where, having, orderby;
    SelectParser selectParser = new SelectParser(); 
    var retMessage = selectParser.Parse("SELECT * FROM T where cat='A' Order by Id desc",
       out fields, out from, out groupby, out where, out having, out orderby);