使用动态SQL检查所有行是否满足条件

时间:2012-12-20 15:13:19

标签: sql sql-server-2008 tsql dynamic-sql

我在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

但是,我不确定嵌套查询是否可以重写为一个,或者在这种情况下是否有更好的方法来测试所有行的有效性?

提前致谢!

3 个答案:

答案 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, '&lt;', '<'), '&gt;', '>'))

这个带有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'