質問

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

やろうとしていること:あるテーブルの既存の計算列(またはデフォルトの制約)が意図した定義に一致するかどうかを判断したい。後者はテーブルの作成に使用されたソフトウェア生成スキーマ。 sp_helptext を使用して計算列の定義を取得し、 sys.default_constraints カタログビューからデフォルトの制約の定義を取得できます。

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

すでに考えた解決策:

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

これを処理するための別の良い選択肢を誰も考えられますか?私の希望は、誰かが正規化/標準形式で入力式を吐き出すデバッグ/診断ツールを知っていることです。

役に立ちましたか?

解決

「正規化」も追加します。式の括弧は、括弧を追加するだけでなく、いくつかの式を非常に異なる方法で変更することもあります!

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

year(getdate()) + 1

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

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

だから、どんな種類のルールや正規表現でも100%のケースであなたの問題を解決するとは思わないので、いくつかの方法を組み合わせることをお勧めします

1)まず最初に、ほとんどのデータベースに存在する典型的な制約の数は限られていると思います。原則として、getdate()と定数数値式(0)、(1)があります。予想される表現と実際の表現を一致させるのに役立つ典型的な制約の表を作成できます。

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

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


編集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();

他のヒント

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

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

ロブ

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

これが探しているものではない場合(完全にクリーンではないことを除けば)、私に知らせてください。必要に応じて調整できます。

ライセンス: CC-BY-SA帰属
所属していません StackOverflow
scroll top