【问题标题】:SQLite take N rows per each groupSQLite 每组取 N 行
【发布时间】:2018-02-19 14:55:29
【问题描述】:

我有一个类似于以下的 SQLite 表:

| A | B |
_________
| e | 5 |
| f | 7 |
| a | 5 |
| n | 7 |
| g | 5 |
| d | 7 |
| i | 5 |
| j | 5 |
| e | 7 |
| v | 7 |

如何在B 列中检索三个值为5 的随机行和三个值为7 的随机行?我不知道B 中的值,也不知道值57我希望B 中的每个不同值有 3 个随机行。 结果可能未按列 B 值分组。可能是这样的:

| A | B |
_________
| e | 5 |
| g | 5 |
| e | 7 |
| v | 7 |
| j | 5 |
| f | 7 |

【问题讨论】:

  • 当你说“随机”时,你的意思是你每次都会得到不同的行选择,由公平的机会决定吗?还是仅仅意味着您不关心获取了哪些行,以便查询可以一遍又一遍地返回相同的结果?
  • 第二个也可以,但第一个会更好

标签: sqlite random limit-per-group


【解决方案1】:

以下几乎可以满足您的需求:

select t.*
from t
where t.rowid in (select t2.rowid
                  from t t2
                  where t2.b = t.b
                  order by random()
                  limit 3
                 );

唉,子查询将针对每一行运行,所以这只是近似值,因为随机数生成器在每次执行时都会更改值。

一种解决方案是使用临时表为每一行存储一个随机数,然后可以将其用于排序。不幸的是,CTE 似乎并不能解决问题,因为每次引用都会重新评估这些。

经过一番思考,我认为临时表可能是唯一的解决方案:

drop table if exists tempt;

create temporary table tempt as 
    select t.*, random() as rand
    from t;

select t.*
from tempt t
where t.rowid in (select t2.rowid
                  from tempt t2
                  where t2.b = t.b
                  order by rand
                  limit 3
                 );

【讨论】:

  • DROP TABLE IF EXISTS tempt开头更好
【解决方案2】:

您可以使用隐藏的 RowID 列来获取每个 B 值的三行,如下所示:

 SELECT A, B FROM T T1
    WHERE RowID IN (SELECT RowID FROM T T2 WHERE B = T1.B LIMIT 3);

请注意,您很可能(但不是 100% 保证)每次都获得相同的三行。如果您想以牺牲一些性能为代价获得随机行,您可以这样做:

 SELECT A, B FROM T T1
    WHERE RowID IN (SELECT RowID FROM T T2 WHERE B = T1.B ORDER BY random() LIMIT 3);

【讨论】:

  • 不知道为什么,但第二个在B 列中的单个值有时会给我 4 有时 2 有时 3 个结果,请参阅 @gordon linoff 的答案
猜你喜欢
  • 1970-01-01
  • 2013-04-25
  • 1970-01-01
  • 2015-03-23
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-09-26
  • 2023-02-02
相关资源
最近更新 更多