0

「曲線」を含む大規模な SQL データベースがあります。各カーブには ID (curveid) があります。各曲線の主なユーザーと、それが使用されているかどうかを判断しようとしています. これを可能にするために、DBA はデータベースに対して実行されたすべてのステートメントのログを提供しています。

これらのステートメントは非常に複雑になる可能性があります。私がやりたいのは、どのcurveidが照会されているかを抽出することだけです。

ステートメントの例は次のとおりです。

WITH G AS ( SELECT [Timevalue] FROM [mc].[GranularityLookup] 
WHERE [TimeValue] BETWEEN '19-Jul-2017 00:00' AND '30-Sep-2017 00:00' 
AND [1 Hr] = 1), 
D AS ( SELECT [CurveID], [DeliveryDate], [PublishDate], AVG([Value]) Value, MAX([PeriodNumber]) PeriodNumber 
FROM mc.CURVEID_6657_1_LATEST data 
JOIN 
(SELECT CurveID ID, DeliveryDate dDate, MAX(PublishDate) pDate 
FROM mc.CURVEID_6657_1_LATEST
WHERE CurveID = 90564
    AND DeliveryDate >= '19-Jul-2017 00:00' AND DeliveryDate <= '30-Sep-2017 00:00'
GROUP BY DeliveryDate,  CurveID ) Dates 
ON data.DeliveryDate = dates.dDate AND data.PublishDate = dates.pDate 
WHERE data.CurveID = 90564
AND data.DeliveryDate >= '19-Jul-2017 00:00' AND data.DeliveryDate <= '30-Sep-2017 00:00'
GROUP BY [CurveID], [PublishDate], [DeliveryDate] )
SELECT 
G.[TimeValue] [Deliver
yDate] , D.[PublishDate], D.[Value], D.[PeriodNumber]
FROM 
G
LEFT JOIN 
D
ON 
G.[TimeValue] = D.[DeliveryDate]
ORDER BY DeliveryDate ASC, PeriodNumber ASC, publishDate DESC

このステートメントから、私が興味を持っているのは、ユーザーがcurveid 90564を照会したことを抽出することだけです.

このステートメントは、次のいずれかに似ている場合もあります。

SELECT * FROM anytable WHERE curveid = 123 AND deliverydate BETWEEN '2017-01-01' AND 2017-02-01'

また

SELECT * FROM mc.anytable WHERE curveid IN (1,2,3,4,5,6,7)

繰り返しますが、私が知りたいのは曲線 ID だけです。他の条項は気にしません。

Microsoft.SqlServer.TransactSql.ScriptDom 名前空間を使用して SQL を解析し、以下のようなコードを使用してすべての WHERE ステートメントを識別できるようになりました (他のいくつかのサンプルからつなぎ合わせました)。

string sql = @"WITH 
            G AS ( SELECT [Timevalue] FROM [mc].[GranularityLookup] 
            WHERE [TimeValue] BETWEEN '19-Jul-2017 00:00' AND '30-Sep-2017 00:00' 
            AND [1 Hr] = 1), 
            D AS ( SELECT [CurveID], [DeliveryDate], [PublishDate], AVG([Value]) Value, MAX([PeriodNumber]) PeriodNumber 
            FROM mc.CURVEID_6657_1_LATEST data 
            JOIN 
            (SELECT CurveID ID, DeliveryDate dDate, MAX(PublishDate) pDate 
            FROM mc.CURVEID_6657_1_LATEST
            WHERE CurveID = 90564
                AND DeliveryDate >= '19-Jul-2017 00:00' AND DeliveryDate <= '30-Sep-2017 00:00'
            GROUP BY DeliveryDate,  CurveID ) Dates 
            ON data.DeliveryDate = dates.dDate AND data.PublishDate = dates.pDate 
            WHERE data.CurveID = 90564
            AND data.DeliveryDate >= '19-Jul-2017 00:00' AND data.DeliveryDate <= '30-Sep-2017 00:00'
            GROUP BY [CurveID], [PublishDate], [DeliveryDate] )
            SELECT 
            G.[TimeValue] [Deliver
            yDate] , D.[PublishDate], D.[Value], D.[PeriodNumber]
            FROM 
            G
            LEFT JOIN 
            D
            ON 
            G.[TimeValue] = D.[DeliveryDate]
            ORDER BY DeliveryDate ASC, PeriodNumber ASC, publishDate DESC";
            var parser = new TSql120Parser(false);

            IList<ParseError> errors;
            var fragment = parser.Parse(new StringReader(sql), out errors);

            var whereVisitor = new WhereVisitor();
            fragment.Accept(whereVisitor);

            //  I now have all WHERE clauses in whereVisitor.WhereStatements

class WhereVisitor : TSqlConcreteFragmentVisitor
{
    public readonly List<WhereClause> WhereStatements = new List<WhereClause>();

    public override void Visit(WhereClause node)
    {
        WhereStatements.Add(node);
    }

}

whereVisitor.WhereStatements の各句 (この例では 3 つ) は、SearchCondition というプロパティを公開します。残念ながら、これは私がアイデアを使い果たしたところです。私が達成したいのは、以下のようなロジックです。

foreach (var clause in whereVisitor.WhereStatements)
{
    //  IF any part of the clause filters based on curveid THEN

    //        Capture curveIDs

    //  END IF
}

その他の詳細:

  • C# (.net 4.0) の使用
  • SQL Server 2008
  • このための DLL は Microsoft.SqlServer.TransactSql.ScriptDom です (私の場合は 'c:\Program Files (x86)\Microsoft SQL Server\130\Tools\PowerShell\Modules\SQLPS\Microsoft.SqlServer.TransactSql.ScriptDom.dll にあります) ')

編集 1

いくつかの追加情報:

  • CurveID は別のテーブルへのキーです。この場合、それを操作しても意味がありません (たとえば、curveId+1 または curveId <= 10)。

編集 2 (部分的な解決策)

次の訪問者を持つことは、節がcurveid = 123に似ている場合に役立ちます:

class CurveIdVisitor : TSqlConcreteFragmentVisitor
{
    public readonly List<int> CurveIds = new List<int>();

    public override void Visit(BooleanComparisonExpression exp)
    {
        if (exp.FirstExpression is ColumnReferenceExpression && exp.SecondExpression is IntegerLiteral )
        {
            //  there is a possibility that this is of the ilk 'curveid = 123'
            //  we will look for the 'identifier'
            //  we take the last if there are multiple.  Example:
            //      alias.curveid
            //  goives two identifiers: alias and curveid
            if (
                ((ColumnReferenceExpression) exp.FirstExpression).MultiPartIdentifier.Identifiers.Last().Value.ToLower() ==
                "curveid")
            {
                //  this is definitely a curveid filter
                //  Now to find the curve id
                int curveid = int.Parse(((IntegerLiteral) exp.SecondExpression).Value);
                CurveIds.Add(curveid);
            }
        }
4

1 に答える 1