使用TSql120Parser

时间:2017-09-11 08:40:35

标签: c# sql sql-server tsql

我正在使用TSql120ParserMicrosoft.SqlServer.TransactSql.ScriptDom)构建SQL查询解析器,并且机制相当简单,将查询分解为批处理并从正确的语句中获取信息。

我有一个问题如何将select语句中的列连接到select语句中的表,让我们使用简单的查询:

SELECT 
    capture_instance as TableName
    , supports_net_changes as SupportNetChanges
    , index_name as PrimaryKeyName 
FROM 
    cdc.change_tables as ChangeTables

我打破了以下语句的查询:

    public void Parse(string query)
    {
        ColumnListInfo = new ColumnInfoList();

        IList<ParseError> parseErrors;
        TSqlFragment result = _sqlParser.Parse(new StringReader(query), out parseErrors);

        if (parseErrors.Any())
        {
            throw new AggregateException(string.Join(Environment.NewLine, parseErrors.SelectMany(error => $"Error: {error.Message}").ToArray()));
        }

        var sqlScript = (TSqlScript)result;
        foreach (TSqlStatement sqlStatement in sqlScript.Batches.SelectMany(sqlBatch => sqlBatch.Statements))
        {
            if (sqlStatement.GetType() == typeof(SelectStatement))
            {
                ProcessSqlSelectStatement(sqlStatement);
            }
            else
            {
                throw new ArgumentException($"Query type not supported: {sqlStatement.GetType()}");
            }
        }
    }

接下来我将获得有关select语句和语句的信息:

    private void GenerateSelectInfo(QuerySpecification querySpecification)
    {
        int selectElementId = 0;

        foreach (SelectElement selectElement in querySpecification.SelectElements)
        {
            if (selectElement.GetType() != typeof (SelectScalarExpression)) continue;

            SelectScalarExpression selectScalarExpression = (SelectScalarExpression)selectElement;
            IdentifierOrValueExpression identifierOrValueExpression = selectScalarExpression.ColumnName;
            var identityString = string.Empty;

            if (identifierOrValueExpression != null)
            {
                if (identifierOrValueExpression.ValueExpression == null)
                {
                    identityString = identifierOrValueExpression.Identifier.Value;
                }
                ColumnListInfo.AddIfNeeded(selectElementId, identityString);

                ScalarExpression scalarExpression = selectScalarExpression.Expression;
                GenerateSelectScalarExperssionRecurse(selectElementId, scalarExpression);
            }
            else
            {
                throw new Exception("Error, something else than SelectScalarExpression found");
            }

            selectElementId++;
        }
    }
    private void GenerateReferenceRecurse(TableReference tableReference)
    {
        if (tableReference.GetType() == typeof(NamedTableReference))
        {
            var namedTableReference = (NamedTableReference)tableReference;
            Identifier aliasIdentifier = namedTableReference.Alias;
            SchemaObjectName schemaObjectName = namedTableReference.SchemaObject;
            ColumnListInfo.AddTableReference(schemaObjectName, aliasIdentifier);
        }
        else if (tableReference.GetType() == typeof(SchemaObjectFunctionTableReference))
        {
            var namedTableReference = (SchemaObjectFunctionTableReference)tableReference;
            Identifier aliasIdentifier = namedTableReference.Alias;
            SchemaObjectName schemaObjectName = namedTableReference.SchemaObject;
            ColumnListInfo.AddTableReference(schemaObjectName, aliasIdentifier);
        }
        else if (tableReference.GetType() == typeof(QualifiedJoin))
        {
            QualifiedJoin qualifiedJoin = (QualifiedJoin)tableReference;
            GenerateReferenceRecurse(qualifiedJoin.FirstTableReference);
            GenerateReferenceRecurse(qualifiedJoin.SecondTableReference);
        }
        else if (tableReference.GetType() == typeof(JoinTableReference))
        {
            JoinTableReference joinTableReference = (JoinTableReference)tableReference;
            GenerateReferenceRecurse(joinTableReference.FirstTableReference);
            GenerateReferenceRecurse(joinTableReference.SecondTableReference);

        }
        else
        {
            throw new ArgumentException($"Not supported table reference : {tableReference.GetType()}");
        }
    }

    private void GenerateSelectScalarExperssionRecurse(int selectElementId, ScalarExpression scalarExpression)
    {
        if (scalarExpression.GetType() == typeof(ColumnReferenceExpression))
        {
            ColumnReferenceExpression columnReferenceExpression = (ColumnReferenceExpression)scalarExpression;
            MultiPartIdentifier multiPartIdentifier = columnReferenceExpression.MultiPartIdentifier;
            ColumnListInfo.AddRefereceIdentifier(selectElementId, multiPartIdentifier);
        }
        else if (scalarExpression.GetType() == typeof(ConvertCall))
        {
            ConvertCall convertCall = (ConvertCall)scalarExpression;
            ScalarExpression scalarExpressionParameter = convertCall.Parameter;
            GenerateSelectScalarExperssionRecurse(selectElementId, scalarExpressionParameter);
        }
        else if (scalarExpression.GetType() == typeof(FunctionCall))
        {
            FunctionCall functionCall = (FunctionCall)scalarExpression;
            Identifier functionIdentifier = functionCall.FunctionName;
            ColumnListInfo.AddFunctionIdentifier(selectElementId, functionIdentifier);
        }
        else
        {
            throw new ArgumentException($"Not supported Expression: {scalarExpression.GetType()}");
        }
    }

我正在使用递归方法,就好像有任何连接,我可以从中获取表信息

但是现在我不知道将表格与哪些列的信息相结合,我试过:

        public void AddTableReference(SchemaObjectName schemaObjectName, Identifier aliasIdentifier)
        {
            if (ColumnList.Count <= 0) return;

            foreach (ColumnInfo columnInfo in ColumnList)
            {
                if (aliasIdentifier != null &&
                    string.Equals(columnInfo.TableAlias, aliasIdentifier.Value, StringComparison.CurrentCultureIgnoreCase))
                {
                    if (schemaObjectName.SchemaIdentifier != null) columnInfo.TableSchema = schemaObjectName.SchemaIdentifier.Value;
                    if (schemaObjectName.BaseIdentifier != null) columnInfo.TableName = schemaObjectName.BaseIdentifier.Value;
                }
                else if (aliasIdentifier == null && schemaObjectName.BaseIdentifier != null &&
                         string.Equals(schemaObjectName.BaseIdentifier.Value, columnInfo.TableAlias, StringComparison.CurrentCultureIgnoreCase))
                {
                    if (schemaObjectName.SchemaIdentifier != null) columnInfo.TableSchema = schemaObjectName.SchemaIdentifier.Value;
                    if (schemaObjectName.BaseIdentifier != null) columnInfo.TableName = schemaObjectName.BaseIdentifier.Value;
                }
            }
        }

但这只适用于连接列,有没有办法?

1 个答案:

答案 0 :(得分:0)

正如Damien_The_Unbeliever所说:

  

块引用   当列名不以表名或别名作为前缀时,您(实际上是SQL Server)无法仅通过解析来确定此信息。您需要查询数据库元数据以确定查询范围内的哪些表包含具有给定名称的列(如果多个表包含具有相同名称的列,则引发错误)