【问题标题】:Left join conditions to convert permutation into combination of rows将排列转换为行组合的左连接条件
【发布时间】:2010-11-25 08:08:49
【问题描述】:

我有一个计划表,例如

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

我通过在其自身上左连接表来生成行的排列(任意次数)。

SELECT t1.id, t2.id, t3.id
FROM plans AS t1 
LEFT JOIN plans AS t2
  ON t1.id != t2.id
  AND ...
LEFT JOIN plans AS t3
  ON t1.id != t2.id AND t2.id != t3.id AND t3.id != t1.id
  AND ...

如何生成提供 service_1 和 service_2 的所有不同组合,同时避免重复。 加入行不能包含相同的服务 例如

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

我正在为这种方法的加入条件而苦苦挣扎。另外,这从根本上来说是解决这个问题的错误方法吗?

我试图避免重复的可能方法是:

  • 有序集(我还没有得到这个工作)例如t1.id

  • sort(array[t1.id,t2.id]) AS ids ... GROUP BY ids

【问题讨论】:

  • 当你说它不能包含相同的服务时,是作为一个完整的行还是单独的服务?因此,例如,第 1 行和第 2 行,它们不是同一行,因为数据是 1,1 和 1,0,因此总体上不同,但是您是否希望它们不匹配,因为两行数据上的 service1 都等于 1 ?

标签: sql mysql postgresql duplicates


【解决方案1】:

另外,这从根本上来说是错误的吗? 解决这个问题的方法?

我想是的。这看起来类似于set packing problem 和/或set cover problem

我认为使用单个查询来执行此操作是不可行的(甚至可能是不可能的)。您需要与要覆盖的服务一样多的连接,并且许多 WHERE 条件是该数量的函数。

我认为简单修剪的天真、蛮力方法可能适用于此,因为无论如何您想要的是所有可能组合的列表。或者您可以预先计算所有有效组合并将它们存储在一个大表中。

无论你做什么,这看起来至少 O(rowscols) 对我有用。

【讨论】:

  • 感谢您的回复。由于数据集的大小以及它会定期更改的事实,似乎不可能预先计算组合。目前,我有根据要比较的服务数量生成查询(连接和条件)的代码。我没有看到避免 O(rows^services) 的方法。
【解决方案2】:

假设你有 id 的 1,2,3 4。SELECT * FROM plans A INNER JOIN plans B ON B.Id >= A.id 会给你以下集合:

1,1
1,2
1,3
1,4
2,2
2,3
2,4
3,3
3,4
4,4

我相信这就是您想要的 - 您的计划中有所有 2 套组合。

【讨论】:

  • 不抱歉。我将一些规则加粗,例如加入行不能包含相同的服务
【解决方案3】:

我认为我们没有足够的表结构/样本输入/样本输出。以下似乎回答了我们正在处理的有限案例的问题:

SELECT
    * /* TODO: Proper column list */
FROM
    plans t1
        left join
    plans t2
        on /* since SQL doesn't have a boolean, are the service columns bit? */
            (t1.service_1 = 0 or t2.service_1 = 0) and
            (t1.service_2 = 0 or t2.service_2 = 0)
WHERE
    (t1.service_1 = 1 or t2.service_1 = 1) and
    (t1.service_2 = 1 or t2.service_1 = 1)

基本上,我们只满足一侧或另一侧存在“间隙”(service_x = 0)的连接,但总体而言,我们要求没有间隙。

对不起,如果这看起来漫无边际,或者不符合要求。如果您可以为您的问题添加更多示例以及实际的表结构,我可能会做得更好。

【讨论】:

  • 看起来与我所做的相似。看看你的答案 - 我想我可能有一些多余的加入条件。如果您的答案不能解决问题,我会更清楚地表达问题。谢谢!
猜你喜欢
  • 2014-02-24
  • 1970-01-01
  • 2015-09-30
  • 2012-03-25
  • 1970-01-01
  • 1970-01-01
  • 2016-05-17
  • 2016-05-12
  • 2016-12-19
相关资源
最近更新 更多