select—如何使用sql从列中获取大于等于列表的25%、50%和75%的值

izkcnapc  于 2021-07-15  发布在  ClickHouse
关注(0)|答案(4)|浏览(790)

我的表只有一列名为 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>),..)

但我不知道该怎么做 <total_row> 参考文献。如果我能 SELECT COUNT(speed) AS total_row ,以后再使用,那就太好了。
非常感谢。

d5vmydt9

d5vmydt91#

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
nhaq1z21

nhaq1z212#

这是一个有点长的评论。
基本上,要在sql中回答这个问题,有三种方法:
窗口功能。
计算累计计数的相关子查询。
具有非相等条件的自连接和计算累积计数的聚合。
第一种方法是迄今为止最好的方法。但另外两个可以在不支持窗口函数的数据库中使用。
唉,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) ;
3htmauhk

3htmauhk3#

抱歉,这不是一个有效但有效的解决方案,请尝试以下操作:
为最大值声明变量:

declare @maxspeed int = (select max(speed) from 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))
zlhcx6iw

zlhcx6iw4#

首先执行自联接,这样每一行都将与所有具有 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和sqlserver。
请看演示。
结果:

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

相关问题