我有一个数据库,其中每个条目都是带有源标签、关系和权重的边。我想在给定源标签的情况下执行查询,我按每个关系的权重与该源标签获取前 n 个边缘。
例如,给定条目
Id Source Relationship End Weight
-----------------------------------------
1 cat isA feline 56
2 cat isA animal 12
3 cat isA pet 37
4 cat desires food 5
5 cat desires play 88
6 dog isA canine 72
如果我使用“cat”作为源进行查询并且n=2,结果应该是
Id Source Relationship End Weight
-----------------------------------------
1 cat isA feline 56
3 cat isA pet 37
4 cat desires food 5
5 cat desires play 88
我根据其他问题尝试了几种不同的方法。
迄今为止最成功的是基于How to SELECT the newest four items per category?
SELECT *
FROM tablename t1
JOIN tablename t2 ON (t1.relationship = t2.relationship)
LEFT OUTER JOIN tablename t3
ON (t1.relationship = t3.relationship AND t2.weight < t3.weight)
WHERE t1.source = "cat"
AND t3.relationship IS NULL
ORDER BY t2.weight DESC;
但是,这会按排序顺序返回所有带有 source="cat"的边。如果我尝试添加 LIMIT,我会得到具有最高权重的边缘,而不是按组。
我尝试过的另一件事是
SELECT *
FROM tablename t1
WHERE t1.source="cat"
AND (
SELECT COUNT(*)
FROM tablename t2
WHERE t1.relationship = t2.relationship
AND t1.weight <= t2.weight
) <= 2;
这会返回
Id Source Relationship End Weight
-----------------------------------------
1 cat isA feline 56
4 cat desires food 5
5 cat desires play 88
因为边 6 的 isA 关系权重高于边 2,但由于 source="dog"而被排除在结果之外
我对数据库非常陌生,所以如果我需要采取完全不同的方法,请告诉我。我不怕重新开始。
最佳答案
使用相关子查询这样做确实效率很低,因为MySQL必须对外部查询的每一行都运行子查询,只是为了判断外部查询中的行是否满足条件。这是很大的开销。
这是一种不使用子查询的方法:
SELECT t1.*
FROM tablename t1
JOIN tablename t2 ON t1.source = t2.source and t1.relationship = t2.relationship
AND t1.weight <= t2.weight
WHERE t1.source = 'cat'
GROUP BY t1.id
HAVING COUNT(*) <= 2;
这是一种既不使用子查询,也不使用 join/group by 的方法:
SELECT *
FROM (
SELECT tablename.*, IF(@r = relationship, @n:=@n+1, @n:=1) AS _n,
@r:=relationship AS _r
FROM (SELECT @r:=null, @n:=1) _init, tablename
WHERE source = 'cat'
ORDER BY relationship, weight DESC
) AS _t
WHERE _n <= 2;
这些解决方案还需要一些决胜局,以防多行具有相同的顶部权重。但这适用于所有解决方案。
更简单的解决方案不需要特殊的体操或决胜局,而是使用 SQL 窗口函数,例如 ROW_NUMBER() OVER(PARTITION BY 关系),但是 MySQL does not support these .
关于mysql - 第二组中每组中最大的 n 个,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/21740440/