4

これは、SQL Server 2005 (またはそれ以降) の計算列と既定の制約 (および場合によっては他の式) に関連しています。これらは両方とも、任意の式を使用して値を生成します。たとえば(year+1)、「来年」を表す計算列などです (これは明らかに単純でばかげた例です)。

私がやろうとしていること:一部のテーブルの既存の計算列 (または既定の制約) が意図した定義と一致するかどうかを判断できるようにしたいと考えています。テーブル。を使用して計算列の定義を取得し、カタログ ビューsp_helptextから既定の制約の定義を取得できます。sys.default_constraints

私が問題を抱えていること:上記のソースから返された式は、列/制約の作成に使用された形式と一致しない正規化/標準形式になっています。上記の例では、SQL は式を に正規化します([year]+(1))。したがって、このフォームと元のフォームの単純な文字列比較では、それらが同じかどうかを確実に判断することはできません。

私がすでに考えた解決策:

  • SQL の形式に一致するように元の式を生成します。これには、文書化されていないフォームを生成するために SQL が使用するルールを知る必要があるため、優れたソリューションではありません。
  • 両方のフォームを解析して AST にし、それらを比較します。私はすでに元のフォームの AST を作成していますが、パーサーを持っていないため、作成したくありません。
  • 一時テーブルを作成し、元の式を使用して計算列を追加してから、正規化された式を読み戻します。これはかなり信頼できますが、理論的にはこの比較は読み取り専用操作であるため、汚い感じがします。

これを処理するための別の良いオプションを考えられる人はいますか? 入力式を正規化/標準形式で吐き出すデバッグ/診断ツールを誰かが知っていることを願っています。

4

3 に答える 3

3

また、式の「正規化」は、括弧を追加するだけでなく、いくつかの式を非常に異なる方法で変更することもあるということも付け加えておきます。

たとえば、MS SQL 2008 Express では、次の式でデフォルトを作成しました。

year(getdate()) + 1

しかし、SQL Serverはそれを次のように変更します

(datepart(year,getdate())+(1))

したがって、どのような種類のルールや正規表現でも問題が 100% 解決するとは思わないので、いくつかの方法を組み合わせることをお勧めします。

1)まず第一に、あなたの場合、ほとんどのデータベースに通常存在する典型的な制約の数は限られていると思います。原則として、getdate()、および定数数値式 (0)、(1) があります。期待される式と実際の式を一致させるのに役立つ典型的な制約の表を用意できます。

2) 次に、すべてのフィールド名を [] 括弧内に含め、すべての定数と数学演算を () 内に含める非常に単純なルールを試すことができるため、年 + 1は([年] + (1))に変換されます。これは正規表現でできると思います。

3) 1 番目または 2 番目の方法を使用して期待される結果と実際の結果を比較できなかったすべてのケースについて、提案したことを行います - 一時テーブルを作成して結果を比較します。


EDIT 04.Aug:

データベース レベルのデフォルトを作成すると、正規化されないことがわかりました。変ですよね?しかし、おそらく、この事実を利用して、列の既定の制約を作成する代わりに、列にバインドするデータベース レベルの既定値を作成することができます (ただし、これは設計上の非常に大きな変更であり、既存のデータベースの大幅な更新が必要になると思います)。

列の既定の制約、および正規化された形式を取得するために既定を動的に作成/削除する方法については、Microsoft.SqlServer.Management.Smo ライブラリを使用した単純な C# コードを次に示します。IntTest int、VarcharTest varchar(1)、DateTimeTest datetime などの列を含む 1 つの test_table を作成することをお勧めします。つまり、各型に対して 1 つの列のみです。この場合、デフォルトを作成/ドロップしますが、ドロップ テーブルと列を作成する必要はなく、これによりパフォーマンスが向上します。

C# コードが続きます (Microsoft.SqlServer.Management.Smo; の使用を含めます)。

        Server server = new Server("localhost\\SQLEXPRESS");
        Database db = server.Databases["test"];
        Table t = db.Tables["test_defaults"];
        //here should be some logic to select column name depending on default data type
        //for example for DateTime defaults we will use "DateTimeTest" column
        Column c = t.Columns["DateTimeTest"];

        //clean up previous results if they exist
        DefaultConstraint constr = c.DefaultConstraint;
        if (constr != null) constr.Drop();

        //create new constraint
        constr = c.AddDefaultConstraint();
        constr.Text = "getdate()";
        constr.Create();
        //after refresh we will have a new text
        constr.Refresh();
        string result = constr.Text;

        //drop it if we don't need it
        constr.Drop();
于 2009-08-03T09:03:14.150 に答える
0

DACに接続して(システムテーブルをクエリできるように)答えがあるはずですが、関数'object_definition'がどのように機能するかを実際に知ることはできません。

これは、Kalen Delaneyのような人にとって、これらのものが解析されるパブリック関数があるかどうかを調べるための質問かもしれません。

ロブ

于 2009-08-03T09:19:40.147 に答える
0

私はあなたの3番目のソリューションに傾倒します(その制約でテーブルを作成し、それを読み戻します)-一時テーブルでそれを行うことができるので、それはセミクリーンであり、正規化されたフォームをキャッシュする場合は、探しているものが変わったときにそれを行う必要があります。検索している式がどれほど静的かはわかりませんが、式が変更された場合は、保存プロセスの一部として、一時テーブルを作成し、制約を適用し、定義から読み取り、それに沿って保存するだけです制約のネイティブ形式で。

これがあなたが探しているものではない場合 (完全にきれいではないことに加えて)、私に知らせてください。必要に応じて調整できます。

于 2009-08-03T17:40:01.920 に答える