选择所有具有最小值的行


9

在Sqlite 3中,我试图弄清楚如何根据最小值选择行。我认为我受限制的原因是对相关术语的了解不足,无法有效地搜索Google。

该表如下所示:

num         text        num2      
----------  ----------  ----------
0           a           1         
0           a           2         
1           a           3         
1           b           4         

我想获得的行num2是1, 2和4。我想基于num的最小值为文本列的每个唯一值进行选择。

因此,对于text = 'a'中,最小值num是0,所以我想行1和2 text = 'b',最小值num是1,所以我想排4。

使用group by的各种组合,我可以获取row 1和2或rows 1and 4。我感觉好像缺少一个可以满足我想要的SQL组件,但是我一直无法弄清楚它可能是什么。

进行此类查询的正确方法是什么?

可能的解决方案

我找到了一种方法。我的声誉不足以回答我自己的问题,因此我在这里进行更新。我不确定这是否总是正确的或者效率是什么样的。欢迎任何意见。

我使用了复合选择语句,其中一个查询为文本的每个唯一值找到num的最小值:

sqlite> select num, text from t group by text having num = min( num );
num         text      
----------  ----------
0           a         
1           b         

然后,我将其与完整表结合在一起,以获取与这两列匹配的所有行。

sqlite> with u as
      ( select num, text from t group by text having num = min( num ) )
        select t.* from t join u on t.num = u.num and t.text = u.text;
num         text        num2      
----------  ----------  ----------
0           a           1         
0           a           2         
1           b           4         

Answers:


10

如您所见,简单的GROUP BY无效,因为每个组仅返回一条记录。

您的加入效果很好。对于大表,仅当联接列(num和text)上有索引时,它才有效。

另外,您可以使用相关子查询:

SELECT *
FROM t
WHERE num = (SELECT MIN(num)
             FROM t AS t2
             WHERE t2.text = t.text);

SQLFiddle

执行该查询时,它不需要临时表(您的查询需要查询的结果u),但将为中的每个记录执行子查询t,因此text应将其编入索引。(或在两者上使用索引,text并num获得覆盖索引。)


他的查询中没有任何临时表,只有CTE,这是完全不同的。
— ypercubeᵀᴹ

执行时,u查询结果存储在临时表中,无论它是作为CTE,视图还是作为子查询内联地编写的。
— CL。

谢谢,这个版本比我偶然发现的版本容易编写。了解正确的术语也有助于我进一步了解这一点。
— user35292 2014年

@CL这就是SQLite如何使用CTE执行查询吗?你有参考吗?因为其他DBMS不一定将临时表用于cte。
— ypercubeᵀᴹ

@ypercube 如果可能,将CTE,视图和子查询展平或实现为协程。但是,非索引列上的GROUP BY必须能够并行收集所有组的数据,因此它需要某种形式的临时表(在所有数据库中)。
— CL。

1

我倾向于通过外部自连接来执行此类操作:

SELECT
    M1.Num,
    M1.Text,
    M1.Num2
FROM
    MyDb M1
LEFT OUTER JOIN
    MyDB M2
ON
    M1.text = M2.text
AND
    M1.num > m2.num
WHERE
    M2.num is null

这基本上是在说;给我所有没有更高价值的记录,即null。


1

那么,下次如何自己找到问题的答案呢?我认为,这是通过分解和遵循逻辑。你说对了:

我想基于文本列的每个唯一值的num的最小值进行选择

转换为:

select text, min(num) from t group by text;

(这应该等效于您的having查询。看一下num等于NULL 的行可能会很有趣。更精确的说:看一下具有null的行有什么作用,您可能需要先使用a过滤掉where num is not null)

在这里,您可以通过以下方式实现所需的结果:

select * from t where (num, text) in ( *insert query above* )

或使用联接:

select t1.* from t t1,
    (select text, min(num) as n from t group by text) t2
where t1.num = t2.n and t1.text = t2.text.

并且当性能不足以支持您的表时,请开始关注更复杂的语句。


-2

该查询不应该正是您所需要的吗?

select min(num), text, num2 group by text, num2

这将返回所有四个记录,因为这些num2值是唯一的。
— CL。
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.