我有一个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)或第三个解决方案的任何建议吗?我对存储过程知之甚少,不知道我能得到多么细粒度。
答案 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)
)