2011-01-19 51 views
3

我们有一个计划表,每个计划都有很多服务。我们想找一个快速的方式查找不包含重复服务但是作为组合包含某些服务的计划组合。生成行组合的最快方法

例如计划表

id | service_1 | service_2 | ... 
--------------------------------- 
1 | true | true  | ... 
2 | true | false | ... 
3 | false | true  | ... 

例如,含SERVICE_1和service_2有效组合

UPDATE

如果有2个服务,我需要他们两个,我们将结合高达2行(或计划),因为它们可能包含在每个最小1个服务。

id | service_1 | service_2 | id | service_1 | service_2 | 
--------------------------------------------------------- 
1 | true | true  |NULL| NULL | NULL | 
2 | true | false | 3 | false | true | 

UPDATE

目前,它的工作原理是自我留下了积极的修剪或行合本身。该查询是基于服务数量动态生成的。它创建了有效连接条件的排列,使其不太实际。

当前成本是按计划数量^服务数量的顺序。

我最感兴趣的是解决这个问题的其他方法,不一定要改进目前的方式。

+1

请发布您迄今为止编写的代码。人们通常不喜欢只为你写代码。事实上,这是一个工作描述,而不是一个问题。 – 2011-01-19 01:57:54

+1

没有足够的信息。您将在搜索中指定多少项服务,以及允许使用多少计划来回答查询? – 2011-01-19 02:11:16

+0

还有什么可以帮到的? – Moriarty 2011-01-19 02:24:18

回答

1

这似乎是工作确定

设置数据

DROP TABLE IF EXISTS plan; 
CREATE TABLE plan (id int, service1 bool, service2 bool, service3 bool); 
INSERT INTO `plan` (`id`, `service1`, `service2`, `service3`) VALUES (1, 1, 0, 0); 
INSERT INTO `plan` (`id`, `service1`, `service2`, `service3`) VALUES (2, 0, 1, 0); 
INSERT INTO `plan` (`id`, `service1`, `service2`, `service3`) VALUES (3, 1, 1, 1); 
INSERT INTO `plan` (`id`, `service1`, `service2`, `service3`) VALUES (4, 1, 0, 1); 
INSERT INTO `plan` (`id`, `service1`, `service2`, `service3`) VALUES (5, 0, 0, 1); 

查询

select * 
from plan A 
left join (
    select id, service1, service2, service3 from plan 
    union all 
    select null, null, null, null) B on B.id > A.id or B.id is null 
left join (
    select id, service1, service2, service3 from plan 
    union all 
    select null, null, null, null) C on C.id > B.id or C.id is null 
WHERE (A.service1 + A.service2 + A.service3) 
    AND (A.service1 + ifnull(B.service1,0) + ifnull(C.service1,0)) = 1 
    AND (A.service2 + ifnull(B.service2,0) + ifnull(C.service2,0)) = 1 
    AND (A.service3 + ifnull(B.service3,0) + ifnull(C.service3,0)) = 1 

结果

id | service1 | service2 | service3 | id | service1 | service2 | service3 | id | service1 | service2 | service3 
1 | 1 | 0 | 0 | 2 | 0 | 1 | 0 | 5 | 0 | 0 | 1 
1 | 1 | 0 | 0 | 5 | 0 | 0 | 1 | 2 | 0 | 1 | 0 
2 | 0 | 1 | 0 | 4 | 1 | 0 | 1 | NULL | NULL | NULL | NULL 
2 | 0 | 1 | 0 | NULL | NULL | NULL | NULL | 4 | 1 | 0 | 1 
3 | 1 | 1 | 1 | NULL | NULL | NULL | NULL | NULL | NULL | NULL | NULL 
1

正如我在评论中提到的,由哪一个规则决定一个“重复”不清楚。然而,从它的声音,你只是做一个按位与。

With RawData As 
    (
    Select 1 As id, 1 As service_1, 1 As service_2 
    Union All Select 2, 1, 0 
    Union All Select 3, 0, 1 
    ) 
    , BinData As 
    (
    Select A.id, A.service_1, A.service_2 
     , A.service_1 * 2 + A.service_2 As Bin 
    From RawData As A 
    ) 
Select * 
From BinData As F1 
    Left Join BinData As F2 
     On F2.id <> F1.id 
      And F1.Bin & F2.Bin = 0 
Order By F1.id 

但是,您将在此解决方案中注意到,我得到id = 3的行。出于同样的原因,id = 3是id = 2的“重复”,反过来也是如此。

如果这是不正确的,我们需要更多的清晰度和一些更好的示例数据来说明什么是和不是“重复”的边缘情况。

更新

考虑什么cyberwiki在评论中指出的那样,如果什么正在寻求每一个计划是联合提供的所有服务恰好一次当另一个计划,则正在寻求的是一个二进制的恭维会产生全部1。我们可以做的是通过查找,当进行XOR运算,目前的计划都计划生产所有的人:

With RawData As 
    (
    Select 1 As id, 1 As service_1, 1 As service_2 
    Union All Select 2, 1, 0 
    Union All Select 3, 0, 1 
    ) 
    , BinData As 
    (
    Select A.id, A.service_1, A.service_2 
     , A.service_1 * 2 + A.service_2 As Bin 
    From RawData As A 
    ) 
Select *, F1.Bin^F2.Bin 
From BinData As F1 
    Left Join BinData As F2 
     On F2.id <> F1.id 
      And F1.Bin^F2.Bin = 3 
Order By F1.id 

再次注意,ID = 3将在结果显示因为正如ID = 3是绝配id = 2,反过来也是如此。