我在SQL Server 2008中有一个表,其中包含以文本形式存储的表达式形式的自定义验证标准,例如
StagingTableID CustomValidation
----------------------------------
1 LEN([mobile])<=30
3 [Internal/External] IN ('Internal','External')
3 ([Internal/External] <> 'Internal') OR (LEN([Contact Name])<=100)
...
我感兴趣的是确定表中的所有行是否都传递了条件语句。为此,我正在编写一个验证存储过程,它检查给定表中给定字段中的所有值是否满足给定条件。 SQL不是我的强项,所以在阅读this questions后,这是我对这个问题的第一次尝试:
EXEC sp_executesql N'SELECT @passed = 0 WHERE EXISTS (' +
N'SELECT * FROM (' +
N'SELECT CASE WHEN ' + @CustomValidationExpr + N' THEN 1 ' +
N'ELSE 0 END AS ConditionalTest ' +
N'FROM ' + @StagingTableName +
N')t ' +
N'WHERE t.ConditionalTest = 0)'
,N'@passed BIT OUTPUT'
,@passed = @PassedCustomValidation OUTPUT
但是,我不确定嵌套查询是否可以重写为一个,或者在这种情况下是否有更好的方法来测试所有行的有效性?
提前致谢!
答案 0 :(得分:1)
在我们回答原始问题之前,您是否考虑过实施约束?这样可以防止错误的数据首先进入您的数据库。或者这些必须在应用程序中动态设置?
ALTER TABLE StagingTable
WITH CHECK ADD CONSTRAINT [StagingTable$MobileValidLength]
CHECK (LEN([mobile])<=30)
GO
ALTER TABLE StagingTable
WITH CHECK ADD CONSTRAINT [StagingTable$InternalExternalValid]
CHECK ([Internal/External] IN ('Internal','External'))
GO
--etc...
答案 1 :(得分:1)
你应该能够减少至少一个这样的子查询:
EXEC sp_executesql N'SELECT @passed = 0 WHERE EXISTS (' +
N'SELECT 1 FROM ' + @StagingTableName +
N'WHERE NOT(' + @CustomValidationExpr + N')) ' +
,N'@passed BIT OUTPUT'
,@passed = @PassedcustomValidation OUTPUT
答案 2 :(得分:0)
您需要将表达式连接在一起。我同意@PinnyM,where
子句更容易进行全表验证。但是,下一个问题将是如何识别哪些行失败了哪些测试。在回答之前我会等你问这个问题(把它作为一个单独的问题而不是作为这个问题的编辑)。
创建where
子句,如下所示:
declare @WhereClause nvarchar(max);
select @WhereClause = (select CustomValidation+' and '
from Validations v
for xml path ('')
) + '1=1'
select @WhereClause = replace(replace(@WhereClause, '<', '<'), '>', '>'))
这个带有for xml path('')
和双精度选择的奇怪构造是在SQL Server中连接值的最方便的方法。
此外,在执行sp_executesql调用之前,将查询放在一起。它为您提供更多灵活性:
declare @sql nvarchar(max);
select @sql = '
select @passed = count(*)
from '+@StagingTableName+'
where '+@WhereClause
这是通过所有验证测试的数字。失败的where
子句是:
declare @WhereClause nvarchar(max);
select @WhereClause = (select 'not '+CustomValidation+' or '
from Validations v
for xml path ('')
) + '1=0'