基于业务规则的动态查询

时间:2019-05-23 16:56:44

标签: tsql

我希望你一切都好。 对于我想自动化的重复性任务,我需要您的帮助和建议。 经理每月都会要求我根据相同的表和列运行一系列SQL查询。 我以为我可以创建一个规则表,让他创建自己的查询 所以我创建了这样的规则表:

enter image description here

基于此表,我想连续执行3个查询。

第一个查询是针对规则“ + NET 3或更多”的,查询如下:

  SELECT * FROM Table Where    
 ([QuestionCode] =  'HSZ' AND ResponseCode = 3)
  OR ([QuestionCode] =  'HSZ' AND ResponseCode = 4)

第二个查询用于“年龄在25-35之间的年龄”规则,查询如下:

SELECT * FROM Table Where    
 ([QuestionCode] =  'RS2' AND ResponseCode >= 25)
  AND ([QuestionCode] =  'RS2' AND ResponseCode < 35)

第三个查询用于规则“ CHN”和“ HSZ”,查询如下:

SELECT * FROM Table Where    
 ([QuestionCode] =  'CHN' AND ResponseCode = 5)
  AND ([QuestionCode] =  'HSZ' AND ResponseCode = 1)

我希望您对此解决方案有意见,尤其是对创建此动态查询有帮助 这是创建规则表的脚本:

    WITH CTE AS 

    (
    SELECT RuleId = 1
     , NetQuestionCode = '+NET 3 or More' 
    , QuestionCategory = 'HSZ'
    , QuestionCode = 'HSZ'
    , ResponseOperator = '='
    , ResponseCode = '3'
    , RuleOrder = '1'
    , CategoryRule = 'OR'

    UNION ALL 
    SELECT RuleId = 1
    , NetQuestionCode = '+NET 3 or More' 
    , QuestionCategory = 'HSZ'
    , QuestionCode = 'HSZ'
    ,ResponseOperator = '='
    , ResponseCode = '4'
    , RuleOrder = '2'
    , CategoryRule = 'OR'

    UNION ALL 
    SELECT RuleId = 2
    , NetQuestionCode = 'Age Between 25-35' 
    , QuestionCategory = 'RS2'
    , QuestionCode = 'RS2'
    ,ResponseOperator = '>='
    , ResponseCode = '25'
    , RuleOrder = '1'
    , CategoryRule = 'and'

    UNION ALL 
    SELECT RuleId = 2
    , NetQuestionCode = 'Age Between 25-35' 
    , QuestionCategory = 'RS2'
    , QuestionCode = 'RS2'
    ,ResponseOperator = '<'
    , ResponseCode = '35'
    , RuleOrder = '2'
    , CategoryRule = 'and'

    UNION ALL
    SELECT RuleId = 3
    , NetQuestionCode = 'CHN AND HSZ' 
    , QuestionCategory = 'CHN'
    , QuestionCode = 'CHN'
    ,ResponseOperator = '='
    , ResponseCode = '5'
    , RuleOrder = '1'
    , CategoryRule = 'and'

    UNION ALL 
    SELECT RuleId = 3
    , NetQuestionCode = 'CHN AND HSZ' 
    , QuestionCategory = 'CHN'
    , QuestionCode = 'HSZ'
    ,ResponseOperator = '='
    , ResponseCode = '1'
    , RuleOrder = '2'
    , CategoryRule = 'and'
    )

    SELECT *
    Into [dbo].[Rules_Parameters]
    FROM CTE

谢谢您的帮助。

1 个答案:

答案 0 :(得分:0)

尝试一下,我基于您的CTE,添加了更多常见的表表达式,以构建WHERE的动态部分,然后使用另一个表达式根据运算符对同一规则的条件进行分组,最后将其移动到将与动态sql一起使用的变量。

declare @DynamicQuery nvarchar(max)=''

; WITH CTE AS 
    (
    SELECT RuleId = 1
     , NetQuestionCode = '+NET 3 or More' 
    , QuestionCategory = 'HSZ'
    , QuestionCode = 'HSZ'
    , ResponseOperator = '='
    , ResponseCode = '3'
    , RuleOrder = '1'
    , CategoryRule = 'OR'

    UNION ALL 
    SELECT RuleId = 1
    , NetQuestionCode = '+NET 3 or More' 
    , QuestionCategory = 'HSZ'
    , QuestionCode = 'HSZ'
    ,ResponseOperator = '='
    , ResponseCode = '4'
    , RuleOrder = '2'
    , CategoryRule = 'OR'

    UNION ALL 
    SELECT RuleId = 2
    , NetQuestionCode = 'Age Between 25-35' 
    , QuestionCategory = 'RS2'
    , QuestionCode = 'RS2'
    ,ResponseOperator = '>='
    , ResponseCode = '25'
    , RuleOrder = '1'
    , CategoryRule = 'and'

    UNION ALL 
    SELECT RuleId = 2
    , NetQuestionCode = 'Age Between 25-35' 
    , QuestionCategory = 'RS2'
    , QuestionCode = 'RS2'
    ,ResponseOperator = '<'
    , ResponseCode = '35'
    , RuleOrder = '2'
    , CategoryRule = 'and'

    UNION ALL
    SELECT RuleId = 3
    , NetQuestionCode = 'CHN AND HSZ' 
    , QuestionCategory = 'CHN'
    , QuestionCode = 'CHN'
    ,ResponseOperator = '='
    , ResponseCode = '5'
    , RuleOrder = '1'
    , CategoryRule = 'and'

    UNION ALL 
    SELECT RuleId = 3
    , NetQuestionCode = 'CHN AND HSZ' 
    , QuestionCategory = 'CHN'
    , QuestionCode = 'HSZ'
    ,ResponseOperator = '='
    , ResponseCode = '1'
    , RuleOrder = '2'
    , CategoryRule = 'and'
    ),WhereCondition as (
        SELECT *,'([QuestionCode] =  '''+QuestionCode+''' AND ResponseCode '+ResponseOperator+' '+ResponseCode+')' [Condition]     FROM CTE
    ),G as (
    select *,cast(Condition as varchar(max)) WhereAll from WhereCondition where RuleOrder=1
    union all
    select c.*,WhereAll+' '+c.CategoryRule+' '+c.Condition from G 
        inner join WhereCondition c on c.RuleOrder=(G.RuleOrder+1) and c.RuleId=G.RuleId
    ),qq as (
    select top(3) 'SELECT * FROM Table Where '+WhereAll+';' [q] from G order by RuleOrder desc
    )
    select @DynamicQuery=@DynamicQuery+q from qq



    EXECUTE sp_executesql @DynamicQuery

或者如果您想从[Rules_Parameters]中进行更改,则更改如下:-

 ;with WhereCondition as (
        SELECT *,'([QuestionCode] =  '''+QuestionCode+''' AND ResponseCode '+ResponseOperator+' '+ResponseCode+')' [Condition]     FROM [dbo].[Rules_Parameters]
    ),G as ( 
        select *,cast(Condition as varchar(max)) WhereAll from WhereCondition where RuleOrder=1
        union all
        select c.*,WhereAll+' '+c.CategoryRule+' '+c.Condition from G 
            inner join WhereCondition c on c.RuleOrder=(G.RuleOrder+1) and c.RuleId=G.RuleId
    ),qq as (
    select top(3) 'SELECT * FROM Table Where '+WhereAll+';' [q] from G order by RuleOrder desc
    )
    select @DynamicQuery=@DynamicQuery+q from qq

EXECUTE sp_executesql @DynamicQuery

无论哪种方式,@ DynamicQuery变量都将包含以下内容:-

SELECT * FROM Table Where ([QuestionCode] =  'CHN' AND ResponseCode = 5) and ([QuestionCode] =  'HSZ' AND ResponseCode = 1);SELECT * FROM Table Where ([QuestionCode] =  'RS2' AND ResponseCode >= 25) and ([QuestionCode] =  'RS2' AND ResponseCode < 35);SELECT * FROM Table Where ([QuestionCode] =  'HSZ' AND ResponseCode = 3) OR ([QuestionCode] =  'HSZ' AND ResponseCode = 4);

希望这就是您想要的。

注意:我没有进行任何验证,例如ResponseOperator可能具有无法运行的操作符并中断了查询等。

注意:我没有使用STRING_AGG,因为您没有提到您的sql数据库版本。