mysql - 第二组中每组中最大的 n 个

标签 mysql greatest-n-per-group

我有一个数据库,其中每个条目都是带有源标签、关系和权重的边。我想在给定源标签的情况下执行查询,我按每个关系的权重与该源标签获取前 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/

相关文章:

php - 我的 PHP 有问题

MySQL 模式设计问题 - 规范化

php - 表单无法添加到wordpress插件子菜单页面

mysql - MySQL 数据库中超出特定列的指定字符范围后出现垃圾字符

mysql - 对 MySQL 数据库中的表进行分组

MySql SELECT 与 GROUP 或 SUBQUERY 与临时表?然后订购了两次?如何?

mysql - 根据两列的不同组合选择最近的行

greatest-n-per-group - Open SQL 中每组的最大 N

选择查询中的 SQL 条件变量

sql - 每组中出现次数最多的值