【问题标题】:How to get values that are >= 25%, 50%, 75% of a list from a column using SQL如何使用 SQL 从列中获取 >= 25%、50%、75% 的值
【发布时间】:2020-04-29 11:22:37
【问题描述】:

我的表有一个名为 Speed(整数)的列,我需要在该列表中选择大于 25%、50%、... 值的值。

样本数据:

+-------+
| Speed |
+-------+
|     1 |
|     2 |
|     3 |
|     4 |
|     5 |
|     6 |
|     7 |
|     8 |
|     9 |
|    10 |
+-------+

期望的输出:

+--------+
| OUTPUT |
+--------+
|      3 |
|      5 |
|      8 |
+--------+

解释:

  • 3 >= 列表中的 25% 数字
  • 5 >= 列表中的 50% 数字
  • 8 >= 列表中的 75% 数字

我认为我应该对数据进行排序,并执行以下操作:

SELECT speed 
FROM my_table
WHERE speed IN (ROUND(0.25 * <total_row>), ROUND(0.50 * <total_row>),..) 

但我不知道如何获得 &lt;total_row&gt; 参考。如果我可以SELECT COUNT(speed) AS total_row,然后再使用它,那就太好了。

非常感谢。

【问题讨论】:

  • Clickhouse 实现了非常有限的 SQL 子集。您还有其他可供数据库使用的选项吗?
  • 我不知道为什么这个问题会被否决。

标签: sql select where-clause clickhouse


【解决方案1】:
create table Speed Engine=Memory 
as select number+1 X from numbers(10);

SELECT quantilesExact(0.25, 0.5, 0.75)(X)
FROM Speed

┌─quantilesExact(0.25, 0.5, 0.75)(X)─┐
│ [3,6,8]                            │
└────────────────────────────────────┘


SELECT arrayJoin(quantilesExact(0.25, 0.5, 0.75)(X)) AS q
FROM Speed

┌─q─┐
│ 3 │
│ 6 │
│ 8 │
└───┘

SELECT arrayJoin(quantilesExact(0.25, 0.499999999999, 0.75)(X)) AS q
FROM Speed

┌─q─┐
│ 3 │
│ 5 │
│ 8 │
└───┘

在 CH 领域 Join 不适用,因为它通常有数十亿行。

create table Speed Engine=MergeTree order by X  as select number X from numbers(1000000000);

SELECT quantilesExact(0.25, 0.5, 0.75)(X)
FROM Speed

┌─quantilesExact(0.25, 0.5, 0.75)(X)─┐
│ [250000000,500000000,750000000]    │
└────────────────────────────────────┘

1 rows in set. Elapsed: 7.974 sec. Processed 1.00 billion rows,

SELECT quantiles(0.25, 0.5, 0.75)(X)
FROM Speed

┌─quantiles(0.25, 0.5, 0.75)(X)────────┐
│ [244782599,500713390.5,751014086.75] │
└──────────────────────────────────────┘

1 rows in set. Elapsed: 1.274 sec. Processed 1.00 billion rows

【讨论】:

  • 由于我使用的是 ClickHouse,所以这个答案是最好的匹配。一般而言,其他答案对 SQL 来说非常有用。
【解决方案2】:

评论有点长。

基本上,要在 SQL 中回答这个问题,有三种方法:

  1. 窗口函数。
  2. 用于计算累积计数的相关子查询。
  3. 具有不相等条件和聚合到计算累积计数的自联接。

第一个是 BY FAR 最好的方法。但是另外两个可以在不支持窗口函数的数据库中使用。

唉,Clickhouse 不支持:

  • 窗口函数。
  • 相关子查询。
  • 非等值连接。

它可能具有支持其中一项或多项功能的未记录功能或扩展。但是,基本产品似乎不支持足够的 SQL 来作为单个查询执行此操作。

编辑:

似乎有办法,假设rowNumberInAllBlocks() 遵循order by 中指定的顺序:

select t.*
from (select t.*,
             rowNumberInAllBlocks() as seqnum,
             tt.cnt
      from t cross join
           (select count(*) as cnt from t) tt
      order by speed
     ) t
where (t.seqnum <= tt.cnt * 0.25 and t.seqnum + 1 > tt.cnt * 0.25) or
      (t.seqnum <= tt.cnt * 0.50 and t.seqnum + 1 > tt.cnt * 0.50) or
      (t.seqnum <= tt.cnt * 0.75 and t.seqnum + 1 > tt.cnt * 0.75) ;

【讨论】:

    【解决方案3】:

    对不起,一个无效但有效的解决方案,试试这个:

    1. 为最大值声明一个 var:

      declare @maxspeed int = (select max(speed) from my_table)
      
    2. 从 my_table 中选择相关值:

      select speed 
      from my_table
      where speed in ((select top 1 speed 
                       from @my_table
                       where speed > 0.25 * @maxspeed),
                      (select top 1 speed 
                       from @my_table
                       where speed > 0.5 * @maxspeed),
                      (select top 1 speed 
                       from @my_table
                       where speed > 0.75 * @maxspeed))
      

    【讨论】:

      【解决方案4】:

      首先,您进行自联接,因此每行都与 Speed 小于或等于行 Speed 的所有行联接。
      然后交叉连接到返回表总行数的查询。
      最后按每个Speed 更大的行的百分比进行分组,四舍五入为整数值25、50 和75,得到每个组的最小Speed

      select min(t.speed) Output 
      from (select count(*) total from tablename) c
      cross join (
        select t.speed, count(*) counter
        from tablename t inner join tablename tt
        on tt.speed <= t.speed
        group by t.speed
      ) t 
      where 25 * floor(floor(100.0 * t.counter / c.total) / 25) in (25, 50, 75)
      group by 25 * floor(floor(100.0 * t.counter / c.total) / 25)
      

      此代码经过测试,适用于 MySql、Postgresql 和 SQL Server。
      请参阅demo
      结果:

      | output |
      | ------ |
      | 3      |
      | 5      |
      | 8      |
      

      【讨论】:

        猜你喜欢
        • 2015-02-21
        • 1970-01-01
        • 2020-01-12
        • 2021-08-10
        • 1970-01-01
        • 2018-05-28
        • 2021-03-27
        • 1970-01-01
        • 2013-08-10
        相关资源
        最近更新 更多