Sql server 一种生成SQL Server的简单方法';s";标准;表达形式?
这与SQLServer2005(或更高版本)中的计算列和默认约束(可能还有其他表达式)有关。这两种方法都使用任意表达式为表示“下一年”的计算列生成值,例如Sql server 一种生成SQL Server的简单方法';s";标准;表达形式?,sql-server,expression-trees,Sql Server,Expression Trees,这与SQLServer2005(或更高版本)中的计算列和默认约束(可能还有其他表达式)有关。这两种方法都使用任意表达式为表示“下一年”的计算列生成值,例如(year+1)(这显然是一个简单而愚蠢的示例) 我想做的是:我想能够确定某个表中现有的计算列(或默认约束)是否与预期定义匹配,后者是在用于创建表的软件生成模式中定义的。我可以使用sp\u helptext获取计算列的定义,并从sys.default\u constraints目录视图获取默认约束的定义 我遇到的问题:我从上述来源得到的表达式是
(year+1)
(这显然是一个简单而愚蠢的示例)
我想做的是:我想能够确定某个表中现有的计算列(或默认约束)是否与预期定义匹配,后者是在用于创建表的软件生成模式中定义的。我可以使用sp\u helptext
获取计算列的定义,并从sys.default\u constraints
目录视图获取默认约束的定义
我遇到的问题:我从上述来源得到的表达式是规范化/标准形式,与用于创建列/约束的形式不匹配。在上面的示例中,SQL将表达式规范化为([year]+(1))
。因此,此表单与原始表单之间的简单字符串比较无法可靠地确定它们是否相同
我已经想到的解决方案:
- 生成原始表达式,使其与SQL的形式匹配。这需要了解SQL用于生成表单的规则,这些规则没有文档记录,因此这不是一个很好的解决方案
- 将这两个表单解析为AST并比较它们。我已经为原始表单编写了一个AST,但是我没有解析器,所以不想编写解析器
- 创建一个临时表并使用原始表达式添加一个计算列,然后读回规范化表达式。这将是相当可靠的,但它感觉脏,因为理论上这种比较应该是只读操作
year(getdate()) + 1
但是SQLServer将其更改为
(datepart(year,getdate())+(1))
所以,我不相信任何类型的规则或正则表达式都能百分之百地解决您的问题,所以我建议您结合使用几种方法
1) 首先,我认为在您的案例中,通常存在于大多数数据库中的典型约束数量有限。通常有getdate()和常量数值表达式(0)、(1)。您可以有一个包含这些典型约束的表,它将帮助您匹配预期表达式和实际表达式
2) 然后,您可以尝试使用非常简单的规则,将所有字段名称包含在[]括号中,将所有常量和数学运算包含在(),这样您就可以将年份+1转换为([year]+(1))。我想这可以通过正则表达式来实现
3) 对于无法使用第1种或第2种方法比较预期结果和实际结果的所有情况,您将按照建议执行-创建临时表并比较结果
8月4日编辑: 我发现,当您创建数据库级别的默认值时,它们不会被规范化。奇怪,嗯?但很可能,您可以使用这个事实创建绑定到列的数据库级默认值,而不是为列创建默认约束(不过,我认为这将是设计上的一个非常大的变化,需要对现有数据库进行大量更新) 至于列的默认约束,以及动态创建/删除默认值以获得其规范化形式的方法,下面是一个使用Microsoft.SqlServer.Management.Smo库的简单C#代码。我建议创建一个包含IntTest int、VarcharTest varchar(1)、DateTimeTest datetime等列的test_表,即每种类型只有一列。在这种情况下,您将创建/删除默认值,但不必创建删除表和列,这将提高性能 随后将是C代码(包括使用Microsoft.SqlServer.Management.Smo;)
我觉得应该通过连接到DAC(这样您就可以查询系统表)来找到答案,但我实际上无法了解函数“object_definition”是如何工作的 这可能是卡伦·德莱尼(Kalen Delaney)这样的人的一个问题,想知道是否有一个公共函数可以解析这些东西
Rob我倾向于第三种解决方案(使用该约束创建一个表,并将其读回)-您可以使用临时表来执行此操作,因此它将是半干净的,如果缓存规范化表单,您只需要在搜索更改时执行此操作。我不确定您正在搜索的表达式的静态程度,但当它们更改时,保存过程的一部分就是创建临时表,应用约束,从定义中读取约束,并将其与约束的本机形式一起保存
如果这不是您想要的(除此之外,它不是完全干净的),请告诉我,我可以根据需要调整它。谢谢您的建议,我同意我可能必须这样做。不过,希望能找到一个更简单的解决方案。如果我最终需要通过临时表进行规范化,我喜欢为此重用一个表的想法。谢谢你所有的好主意。
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();