一个简单的方法来生成一个表达式的SQL Server的“标准”的形式?(a simple way t

2019-09-21 11:15发布

这在SQL Server 2005(或以上)涉及计算列和默认约束(以及可能的其他表达式)。 这两种使用任意的表达,以产生一个值,例如(year+1)用于表示“明年”计算列(这显然是一个简单的和笨例子)。

我想要做的事:我希望能够确定一些表中的现有计算列(或默认约束)是否预期的定义,其中后者在被用于创建软件生成的架构中定义匹配表。 我可以使用计算列的定义sp_helptext ,并从默认的约束定义sys.default_constraints目录视图。

就是我遇到的麻烦:我从上述来源回是在标准化/标准形式,不用于创建列/约束形式相匹配的表达。 在上面的例子中,SQL标准化的表达, ([year]+(1)) 因此,这种形式和原始形式之间的简单字符串比较就不能可靠地确定它们是否是相同的。

解决方案我认为已经:

  • 生成原始表达式,使它们符合SQL的形式。 这需要了解SQL用来生成它的形式,这是没有记录的规则,所以它不是一个很好的解决方案。
  • 解析两种形式进入的AST和比较这些。 我已经为原始形式的AST,但我没有一个解析器,宁可不写一个。
  • 创建一个临时表,并添加使用原始表达式计算列,然后回读标准化表达。 这将是非常可靠的,但感觉脏,因为在理论上这种比较应该是一个只读操作。

谁能想到处理这个另一种很好的选择? 我的希望是,也许有人一些调试/诊断工具,将在标准化/标准形式吐回输入表达式的认识。

Answer 1:

我也将增加,这表达的“正常化”有时不仅增加了括号,但它也改变了一个非常不同的方式表达一些!

例如,在MS SQL 2008 Express的我创建了下面的表达式默认:

year(getdate()) + 1

但SQL Server更改它是

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

所以,我不相信任何形式的规则或正则表达式将解决你的问题的情况下100%的,所以我建议你几种方法结合起来

1)所有我认为你的情况有典型的限制数量有限首先,通常存在于大多数的数据库。 作为一项规则,有GETDATE(),和恒定的数值表达式(0),(1)。 你可以有这些典型的约束,这将帮助您匹配的预期和实际表达的表格。

2)然后,你可以尝试非常简单的规则,包括在括号[]中的所有字段名和所有的常量和数学运算(),这样你才会有一年+ 1转化成([年] +(1))。 我想这可能是与一个正则表达式来完成。

3)在您使用1号或2号方法无法比拟预期和实际结果所有的情况下,你会做你的建议 - 创建临时表,并比较结果。


编辑04.Aug:

我发现,当你创建一个数据库级的默认值,他们不会正常化。 奇怪,不是吗? 但或许,你可以利用这一点,并创建绑定到列,而不是为列创建默认约束数据库级的默认值(不过,我想这将是在设计一个非常大的变化,将需要对现有数据库的巨大更新)

作为列的缺省限制,以及创建/以获得他们的规范化的形式动态下降默认的方法,这里是使用Microsoft.SqlServer.Management.Smo库一个简单的C#代码。 我会建议建立一个与TEST_TABLE INT IntTest,VarcharTest VARCHAR(1),DateTimeTest日期时间等列 - 即只为每种类型的一列。 在这种情况下,您将创建/删除默认值,但不会有创建删除表和列,这将提高性能。

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


Answer 2:

我觉得应该通过连接到DAC(这样就可以查询系统表)是答案,但我不能真正找出功能“OBJECT_DEFINITION”是如何工作的。

这可能是对于像卡伦·德莱尼一个问题,以找出是否有一个公共职能,这些东西得到与解析。



Answer 3:

我对你的第三个解决方案精益(创建表与约束和读回) - 你可以用一个临时表做到这一点,所以这将是半干净,如果缓存规范化格式,你只需要做的是,当你搜索的内容变化。 我不知道你要搜索的表现如何静态的,但是当他们改变,只是有保存过程的一部分,它会创建一个临时表,适用的约束,自定义读它,并沿其保存与约束的原生形态。

如果这不是你要找的是什么(除了它不是一个完全干净的),让我知道,如需要,我可以调整。



文章来源: a simple way to generate SQL Server's “standard” form of an expression?