如何使用“NOT IN (a,b,c)”逻辑构建决策表?

Posted

技术标签:

【中文标题】如何使用“NOT IN (a,b,c)”逻辑构建决策表?【英文标题】:How to build a decision table with "NOT IN (a,b,c)" logic? 【发布时间】:2022-01-13 10:22:46 【问题描述】:

假设有一个用于派生值的业务规则,并且由于业务用户需要对其进行更新,因此逻辑必须保存在表中而不是函数中。

当前函数示例

 WHEN inputA IN (1,2,3) AND inputB NOT IN (55,66) THEN OUTPUT = 'HQ'
 WHEN inputA IN (3,6)   AND inputB     IN (27,44) THEN OUTPUT = 'Northern'
 WHEN inputC IN (6,4,1) AND inputB NOT IN (55,66) THEN OUTPUT = 'Eastern'
 etc.

我可以为每个组合构建一个包含一行的表格 例如

OUTPUT A val B val C val D val ...
Northern 3 27
Northern 3 44
Northern 6 27
Northern 6 44

那么如何建模这个“NOT IN”部分呢?

肯定有一种方法可以让我不必创建所有可能需要根据更改的参考数据进行更新的“异常”行?

【问题讨论】:

输入列数有限制吗? 您是否只是在寻找一种表示这些表达式的方法? 这实际上看起来类似于我的一位同事前一周遇到的问题,但增加了额外的任意列的复杂性。我可能可以改变我在那里所做的事情,因为我仍然有脚本,但是如果我要接受这些有意义的示例数据和预期结果,那将非常有用。 所以它可以?您的措辞表明列需要是动态的;如果是这样,那么您将进入一个受伤的世界。如果是这种情况,那么可能需要进行根本的重新设计。 您在“密集定义”中定义了一组规则,并且您正试图将其转换为“扩展定义”。可以在 IN 部分的单个集合中执行此操作,但不能使用 NOT IN 部分。现在,您可以生成一个更复杂的模型(单独的表或表达式组装)来对这些规则进行建模,但它不会像您想要的那样直接。 【参考方案1】:

您可以用每行包含的表格来表示这些表达式:

输出 等于? (对或错) 输入 价值

这将表示“如果(输入 = 值)= 等于?然后输出”,除了对于给定的输出/输入,您只需要 1 个令人满意的行,其中等于?是真的,但所有行必须满足 EQUALS?是假的。

这假设您对每个不同的输出只有一个“规则”。

【讨论】:

【参考方案2】:

这里尝试使用带有正负规则的规则表。

规则表将有效值存储为整数,而将无效值存储在带有分隔符的字符串中。 (不确定是json还是xml更好)

但是有负面规则真的很棘手。 因为通过为相同的输出名称添加另一个规则很容易忽略规则。

我个人认为对这类规则使用 UDF 更安全。

create table test (
 id int identity(1,1) primary key, 
 inputA int, 
 inputB int, 
 inputC int
)

create table output_areas (
 code varchar(2) primary key, 
 name varchar(30) not null
)

insert into output_areas values
  ('HQ', 'HQ')
, ('N', 'Northern'), ('E', 'Eastern')
, ('W', 'Westhern'), ('S', 'Southern')
, ('X', 'Extern'), ('Z', 'The Zone')


create table input_rules (
 id int identity(1,1) primary key, 
 output_area_code varchar(2) not null,
 relevance int not null default 0,
 inputA_valid int,
 inputB_valid int,
 inputC_valid int, 
 inputA_invalid varchar(100),
 inputB_invalid varchar(100),
 inputC_invalid varchar(100),
 foreign key (output_area_code) references output_areas(code)
)


insert into input_rules (output_area_code, relevance) 
values ('X', 0);

insert into input_rules (output_area_code, relevance, inputA_valid) 
values ('Z',10, 1);

insert into input_rules (output_area_code, relevance, inputA_valid, inputB_invalid) 
values
  ('HQ', 20, 1, '|55|56|')
, ('HQ', 20, 2, '|55|56|')
, ('HQ', 20, 3, '|55|56|')
;
insert into input_rules (output_area_code, relevance, inputA_valid, inputB_valid) 
values
  ('N', 30, 3, 27), ('N', 30, 3, 44)
, ('N', 30, 6, 27), ('N', 30, 6, 44)
;
insert into input_rules (output_area_code, relevance, inputC_valid, inputB_invalid) 
values
  ('E', 20, 6, '|55|66|' )
, ('E', 20, 4, '|55|66|' )
;


insert into test 
  (inputA, inputB, inputC) values 
  (1, 56, null)
, (3, 44, null), (3, 66, null)
, (1, 66, null), (1, 88, null)
, (null, 66, 6), (null, 88, 6)
select * from input_rules
编号 |输出区域代码 |相关性 | inputA_valid | inputB_valid | inputC_valid | inputA_invalid | inputB_invalid | inputC_invalid -: | :--------------- | --------: | ------------: | ------------: | ------------: | :------------- | :------------- | :------------- 1 | X | 0 | | | | | | 2 | Z | 10 | 1 | | | | | 3 |总部 | 20 | 1 | | | | |55|56| | 4 |总部 | 20 | 2 | | | | |55|56| | 5 |总部 | 20 | 3 | | | | |55|56| | 6 | N | 30 | 3 | 27 | | | | 7 | N | 30 | 3 | 44 | | | | 8 | N | 30 | 6 | 27 | | | | 9 | N | 30 | 6 | 44 | | | | 10 | E | 20 | | | 6 | | |55|66| | 11 | E | 20 | | | 4 | | |55|66| |
select *
from test t
outer apply (
  select top 1 ref.name as output
  from input_rules r
  join output_areas ref on ref.code = r.output_area_code
  where (r.inputA_valid is null or r.inputA_valid = t.inputA) 
    and (r.inputB_valid is null or r.inputB_valid = t.inputB) 
    and (r.inputC_valid is null or r.inputC_valid = t.inputC)
    and (r.inputA_invalid is null or r.inputA_invalid not like concat('%|', t.inputA, '|%')) 
    and (r.inputB_invalid is null or r.inputB_invalid not like concat('%|', t.inputB, '|%')) 
    and (r.inputC_invalid is null or r.inputC_invalid not like concat('%|', t.inputC, '|%')) 
  order by r.relevance desc, r.output_area_code asc
) ca
编号 |输入A |输入B |输入C |输出 -: | -----: | -----: | -----: | :-------- 1 | 1 | 56 | |专区 2 | 3 | 44 | |北方 3 | 3 | 66 | |总部 4 | 1 | 66 | |总部 5 | 1 | 88 | |总部 6 | | 66 | 6 |外部 7 | | 88 | 6 |东

db小提琴here

【讨论】:

以上是关于如何使用“NOT IN (a,b,c)”逻辑构建决策表?的主要内容,如果未能解决你的问题,请参考以下文章

如何决定为基于规则的系统创建哪些单元测试

通用 DAL / BLL 类

如果我有 2 个具有相同视图但逻辑不同的 Angular 组件,如何正确构建代码?

JavaScript 如何决定为数值分配多大的内存?

面相对象

构建日历时如何分离逻辑和表示代码?