Mysql 第二组中每个组的最大n个
我有一个数据库,其中每个条目都是一个带有源标记、关系和权重的边。我想执行一个查询,在给定一个源标记的情况下,我通过权重获得每个关系的前n条边 例如,给定条目Mysql 第二组中每个组的最大n个,mysql,greatest-n-per-group,Mysql,Greatest N Per Group,我有一个数据库,其中每个条目都是一个带有源标记、关系和权重的边。我想执行一个查询,在给定一个源标记的情况下,我通过权重获得每个关系的前n条边 例如,给定条目 Id Source Relationship End Weight ----------------------------------------- 1 cat isA feline 56 2 cat isA animal 12 3
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
基于其他问题,我尝试了几种不同的方法
迄今为止最成功的是基于
因为边缘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;
选择t1*
来自表名t1
在t1.source=t2.source和t1.relationship=t2.relationship上联接表名t2
t1.weight虽然效率不会太高,但MySQL允许您执行以下操作:
SELECT t1.*
FROM
tablename t1 INNER JOIN (
SELECT SUBSTRING_INDEX(
GROUP_CONCAT(Id ORDER BY Weight DESC),
',',
2) top_2
FROM tablename
WHERE Source='cat'
GROUP BY Relationship) t2
ON FIND_IN_SET(t1.id, t2.top_2);
请看小提琴。这个很好用。快得多。最后一个问题,第二个代码建议是否有任何理由不能与mysqli一起使用?通过命令行直接与mysql一起使用时,我得到了107行,但通过mysqli使用时,只有28行。似乎@n
需要初始化为非空值。我编辑了上面的内容来说明这一点。这样效果更好。对不起,我想我已经测试过了。
Id Source Relationship End Weight
-----------------------------------------
1 cat isA feline 56
4 cat desires food 5
5 cat desires play 88
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;
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;
SELECT t1.*
FROM
tablename t1 INNER JOIN (
SELECT SUBSTRING_INDEX(
GROUP_CONCAT(Id ORDER BY Weight DESC),
',',
2) top_2
FROM tablename
WHERE Source='cat'
GROUP BY Relationship) t2
ON FIND_IN_SET(t1.id, t2.top_2);