Sql server SQL中的动态运算符

Sql server SQL中的动态运算符,sql-server,tsql,sql-server-2016,Sql Server,Tsql,Sql Server 2016,假设我有下表tbl_规则: RuleID NameOperator NameValues TypeOperator TypeValue 1 NotIn John In 2 1 NotIn Alex In NULL 1 NotIn Mike In

假设我有下表tbl_规则:

RuleID  NameOperator     NameValues   TypeOperator   TypeValue    
1       NotIn               John         In             2
1       NotIn               Alex         In            NULL
1       NotIn               Mike         In            NULL  
2        In                 Mike         NotIn          2
我的源表看起来像这个tbl_源:

 ID Name   Type Cost  
 1  Mike    2   100   
 2  Cole    2   200  
 3  Ken     1   300  
 4  Tara    1   400  
 5  Mike    1   500
 6  Sonya   1   600 
 7  Ann     2   700
 8  Mike    1   800
我希望能够联接这两个表并得到以下结果tbl_结果:

RuleID  Name  Type  Cost
  1     Cole   2    200
  1     Ann    2    700  
  2     Mike   1    500  
  2     Mike   1    800   
如果我手动编写此查询,我的查询将如下所示:

select 1, Name, Type, Cost 
from tbl_Source 
Where Name not in ('John', 'Alex', 'Mike') and Type in (2) 
union all
select 2, Name, Type, Cost
from tbl_Source
where Name in ('Mike') and Type not in (2)
在我当前的设置中,tbl_规则有500条记录,tbl_源有500k条记录

我们非常感谢您对此提出的任何建议。限制: 无CLR功能,无2017功能(例如字符串_agg)


更新:以上示例的DDL语句可以在这里找到:

这里是一种方法。我使用了
交叉连接
来检查规则。在
join

declare @tbl_Rules table(
    RuleID int
    , NameOperator varchar(20)
    , NameValues varchar(20)
    , TypeOperator varchar(20)
    , TypeValue int
)
insert into @tbl_Rules
values 
(1, 'NotIn', 'John', 'In', 2)
, (1, 'NotIn', 'Alex', 'In', NULL)
, (1, 'NotIn', 'Mike', 'In', NULL)
, (2, 'In', 'Mike', 'NotIn', 2)

declare @tbl_Source table (
    ID int
    , Name varchar(20)
    , Type int
    , Cost int
)
insert into @tbl_Source
values
(1, 'Mike', 2, 100)
, (2, 'Cole', 2, 200)
, (3, 'Ken', 1, 300) 
, (4, 'Tara', 1, 400)
, (5, 'Mike', 1, 500)
, (6, 'Sonya', 1, 600) 
, (7, 'Ann', 2, 700)
, (8, 'Mike', 1, 800)

;with cte as (
    select
        distinct Ruleid, a.NameOperator, a.TypeOperator
         , NameValues = (
            select
                '!' + b.NameValues
            from
                @tbl_Rules b
            where
                a.RuleID = b.RuleID
                and b.NameValues is not null
            for xml path('')
        ) + '!'
        , TypeValue = (
            select
                concat('!', b.TypeValue)
            from
                @tbl_Rules b
            where
                a.RuleID = b.RuleID
                and b.TypeValue is not null
            for xml path('')
        ) + '!'
    from 
        @tbl_Rules a
)

select
    b.RuleID, a.Name, a.Type, a.Cost
from
    @tbl_Source a
    cross join cte b
where
    1 = case
        when b.NameOperator = 'In' and charindex('!' + a.Name + '!', b.NameValues) > 0 and b.TypeOperator = 'In' and charindex(concat('!', a.Type, '!'), b.TypeValue) > 0 then 1
        when b.NameOperator = 'In' and charindex('!' + a.Name + '!', b.NameValues) > 0 and b.TypeOperator = 'Notin' and charindex(concat('!', a.Type, '!'), b.TypeValue) = 0 then 1
        when b.NameOperator = 'NotIn' and charindex('!' + a.Name + '!', b.NameValues) = 0 and b.TypeOperator = 'In' and charindex(concat('!', a.Type, '!'), b.TypeValue) > 0 then 1
        when b.NameOperator = 'NotIn' and charindex('!' + a.Name + '!', b.NameValues) = 0 and b.TypeOperator = 'NotIn' and charindex(concat('!', a.Type, '!'), b.TypeValue) = 0 then 1
        else 0
    end
输出:

RuleID   Name   Type   Cost
---------------------------
1        Cole   2      200
1        Ann    2      700
2        Mike   1      500
2        Mike   1      800
你可以试试这个

SELECT MAX(R_N.RuleID) RuleID,  S.Name, S.Type, S.Cost 
FROM tbl_Source S
    INNER JOIN tbl_Rules R_N ON 
           (R_N.NameValues <> S.Name and R_N.NameOperator = 'NotIn' )
        OR (R_N.NameValues = S.Name and R_N.NameOperator = 'In' )
    INNER JOIN tbl_Rules R_S ON 
           R_S.RuleID = R_N.RuleID AND
           (R_S.TypeValue <> S.Type and R_S.TypeOperator = 'NotIn' )
        OR (R_S.TypeValue = S.Type and R_S.TypeOperator = 'In' )
GROUP BY 
    S.Name, S.Type, S.Cost
HAVING
    MAX(R_N.NameOperator) = MIN(R_N.NameOperator) 
    AND MAX(R_S.TypeOperator) = MIN(R_S.TypeOperator) 

我很好奇,你为什么在SQL中这么做?@MikeDinescu,问得好。这是我们当前的设置,无法在代码中完成。但是,即使我们在代码中这样做,看起来也会慢得多。(正如我所提到的,表中有500k条记录,列数比本例中的多)在
tbl_规则
中,值列中NULL的含义是什么?此外,值列可以保存csv类值
1,2
,还是只保存一个值?@ZoharPeled,只保存一个值。我们需要NULL的原因是,对于NameValue,我们有3条记录,对于TypeValue,我们有1条记录。空值可以忽略,因为它看起来像预期的那样工作。我有一个问题:在我的真实场景中,我有四个过滤参数,而不是两个。(在我上面的例子中,我有Name+Type,但实际上我有Name+Type+LastName+ReferenceNumber。所以,看起来我需要写16个case-WHEN语句。你知道这是否可以用一种更简单的方式实现吗?我认为用这种方式是不可能的。
RuleID      Name                 Type        Cost
----------- -------------------- ----------- -----------
1           Ann                  2           700
1           Cole                 2           200
2           Mike                 1           500
2           Mike                 1           800