0

我有一个 mysql 表,其中包含来自许多不同来源的结果,基本上是列:

id     (PRIMARY KEY)
source (INT)
value  (VARCHAR)
score  (FLOAT)

例子

id source value score
-- ------ ----- -----
1    1     dog   0.2
2    1     cat   2.5
3    1     pig   4.0
4    2     dog   2.3
5    2     dog   1.5
6    2     cat   1.4
7    2     hen   0.7

我需要对sources执行 set 操作,例如1 ∩ 2 ∩ 3or (1 + 2 + 3) ∩ (4 + 5 + 6)(其中 + 表示联合),但使用该作为键,并返回完整的行。我正在将表达式转换为选择语句(每个嵌套的子表达式都成为一个选择)。这些是网络上的请求,因此性能是一个问题,但另一方面,我将在初始请求后缓存结果。

让我们看看如何根据值查询两个源的交集中的行,1 ∩ 2以示例为例。我可以

SELECT value
FROM table
WHERE source=1 OR source=2
GROUP BY value HAVING COUNT (DISTINCT source) = 2

而且,我什至可以用

SELECT table.id, table.value, table.source
FROM (
    SELECT value
    FROM table
    WHERE source=1 OR source=2
    GROUP BY value HAVING COUNT (DISTINCT source) = 2) AS intersection
JOIN table ON intersection.value = table.value
WHERE table.source=1 or table.source=2

屈服

id source value score
-- ------ ----- -----
1    1     dog   0.2
2    1     cat   2.5
4    2     dog   2.3
5    2     dog   1.5
6    2     cat   1.4

但是,对于我需要处理的嵌套表达式,它不是一个易于使用的解决方案,因为它会返回到原始表并再次基于源进行限制。考虑寻找两个选择结果的交集,其中每个选择语句生成数据表的一个子集。我不能再加入全桌了。我必须加入两个选择的联合的交集,但这似乎根本无法扩展。

我认为的另一种方法是在 id 上使用 GROUP_CONCAT,然后将 id 列表拆分回行(在存储过程或 python 中)。该存储过程让我想到,也许我应该为整个查询编写自己的过程。

那么,是否有另一种方法可以使用 vanilla sql 进行这些查询?如果没有,我会尝试编写一个存储过程(以前从未做过,应该很有趣)。存储过程是最好的方法吗?关于使用第一个解决方案(临时表和连接)、第二个解决方案(group_concat 和 split)或完全使用第三个解决方案的任何建议?我对存储过程知之甚少,不知道我能得到多细的粒度。

4

1 回答 1

0

基于此语句“具体来说,如何根据值查询两个源的交集中的行?”,您似乎想要指定一个或多个源并返回所有具有匹配值的行。

select *
from t
where t.source in (select 1 as source union all select 2 as source) and
      t.value in (select value
                  from (select 1 as source union all select 2 as source) sources join
                       t
                       on t.source = sources.source
                  group by value
                  having count(distinct t.source) = 2
                 )

在此版本中,您必须两次输入源列表(一次在子查询中,一次在外部查询中)并硬编码数字“2”。在其他数据库中,这很容易使用“with”子句将列表定义为可以在整个查询中重复使用的别名,但 mysql 不支持这一点。

如果将源列表放在名为 s 的表中,则可以使用:

select *
from t
where t.source in (select source from s) and
      t.value in (select value
                  from s join
                       t
                       on t.source = s.source cross join
                       (select count(*) as cnt from s) const
                  group by value
                  having count(distinct t.source) = max(const.cnt)
                 )
于 2012-08-15T17:48:24.140 回答