如何对特定列上的两个选择的结果进行分组和交叉,然后从两个列中返回所有匹配的行?

时间:2012-08-15 17:16:14

标签: mysql stored-procedures intersection

我有一个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

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

让我们看一下如何使用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

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

我认为不同的方法是在ID上使用GROUP_CONCAT,然后将ID列表拆分回行(在stored procedure或python中)。那个存储过程让我觉得我可能只是为整个查询编写自己的程序。

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

1 个答案:

答案 0 :(得分:0)

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

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)
                 )