【问题标题】:Fastest way to generate combinations of rows生成行组合的最快方法
【发布时间】:2011-06-11 11:41:27
【问题描述】:

我们有一个计划表,每个计划都有许多服务。我们想要一种快速找到不包含重复服务但组合包含某些服务的计划组合的方法。

例如计划表

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

例如包含 service_1 和 service_2 的有效组合

更新

如果有 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   |

更新

它目前通过自我左加入自身进行积极的修剪或行。查询是根据服务数量动态生成的。它会创建有效连接条件的排列,使其不实用。

目前费用按计划数量^服务数量的顺序排列。

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

【问题讨论】:

  • 请贴出你目前写的代码。人们通常不喜欢只为您编写代码。事实上,这是一个工作描述,而不是一个问题。
  • 信息不足。您将在搜索中指定多少服务,以及允许使用多少计划来回答查询?
  • @mitch 刻薄,嗯? “它目前通过自我左连接自身与积极的修剪或行来工作。”对我来说,这充分描述了一个可能的当前解决方案,我可以想象它如何花费“计划数量 ^ 服务数量”。
  • @cyberkiwi:我的评论是在海报更新他的问题之前发表的。请把你的事实弄清楚。
  • @Mitch - 这个问题 (rev1) 具有足够的挑战性,可以攻击。如果您不同意,请随时查看问题的背面,或者您可以投反对票以查看其他人是否同意。

标签: sql performance optimization postgresql


【解决方案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

【讨论】:

  • 该模式通过左连接和 where 子句中的 AND 行进行扩展,但除此之外,没有要考虑的排列的指数/多项式扩展。
  • 太棒了,我会试一试的。
  • 如果你错过了,我把“C.id > A.id or C.id is null”改为“C.id > B.id or C.id is null”
  • 是的,订购它们。为此干杯。我去测试一下。
  • 该死的。速度相同,但比当前代码干净得多。非常感谢。如果没有更快的速度出现,您会得到答案。
【解决方案2】:

正如我在 cmets 中提到的,确定“重复”的规则尚不清楚。然而,从它的声音来看,你只是在做一个按位与。

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在cmets中所说的,如果每个计划所寻求的是另一个计划,当组合时,它只提供一次所有服务,那么所寻求的是一个二进制的恭维,它将产生所有的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 *, 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 完美匹配一样,反之亦然。

【讨论】:

  • 非常感谢托马斯。我会尝试移动一些位,看看它的表现如何。
猜你喜欢
  • 2010-10-26
  • 1970-01-01
  • 1970-01-01
  • 2022-10-04
  • 1970-01-01
  • 1970-01-01
  • 2013-10-12
  • 2013-12-05
  • 1970-01-01
相关资源
最近更新 更多