sql-server - 生成 SQL Server "standard"形式的表达式的简单方法?

标签 sql-server expression-trees

这与 SQL Server 2005(或更高版本)中的计算列和默认约束(可能还有其他表达式)有关。这两者都使用任意表达式来生成值,例如(year+1) 用于表示“明年”的计算列(这显然是一个简单而愚蠢的示例)。

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

我遇到的问题:我从上述来源返回的表达式采用规范化/标准形式,与用于创建列/约束的形式不匹配。在上面的示例中,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) 对于无法使用第一种或第二种方法比较预期结果和实际结果的所有情况,您将按照您的建议进行操作 - 创建临时表并比较结果。

<小时/>

编辑 8 月 4 日:

我发现当您创建数据库级默认值时,它们不会被规范化。奇怪吧?但也许,您可以使用这个事实并创建绑定(bind)到列的数据库级默认值,而不是为列创建默认约束(不过,我认为这将是设计上的一个非常大的变化,并且需要对现有数据库进行大量更新)

对于列默认约束,以及动态创建/删除默认值以获得其规范化形式的方法,这里是使用 Microsoft.SqlServer.Management.Smo 库的简单 C# 代码。我建议创建一个包含 IntTest int、VarcharTest varchar(1)、DateTimeTest datetime 等列的 test_table - 即每种类型只有一列。在这种情况下,您将创建/删除默认值,但不必创建删除表和列,这将提高性能。

接下来将使用 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();

关于sql-server - 生成 SQL Server "standard"形式的表达式的简单方法?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/1206514/

相关文章:

sql-server - SQL Server : One Table with 400 Columns or 40 Tables with 10 Columns?

sql - 没有系统管理员权限的 OpenRowSet 和 OpenDataSet

c# - 在没有数据库上下文的情况下将 LINQ 表达式转换为 SQL 文本

java - 是否有 TreeVisitor 用于按评估顺序访问表达式树?

c# - 从数据库问题下载 ASP.NET MVC 3 文件

SQL唯一字段: concurrency bugs?

sql-server - 将 Excel 与 SQL Server 集成

C# 在 lambda 表达式中切换

c# - String.Contains 和 string[] 的表达式生成器函数

c# - 从 Linq 表达式中获取参数值