选择所有具有最小值的行


9

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

该表如下所示:

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

我想获得的行num21, 24。我想基于num的最小值为文本列的每个唯一值进行选择。

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

使用group by的各种组合,我可以获取row 12或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无效,因为每个组仅返回一条记录。

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

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

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

SQLFiddle

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


他的查询中没有任何临时表,只有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.