Sql server SQL中的动态运算符
假设我有下表tbl_规则: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
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