当前位置: 首页 > 知识库问答 >
问题:

如何在红移中实现窗口化的运行中位数?

萧波峻
2023-03-14

我正在拉出我的头发,试图按时间顺序创建分区值的运行/累积中位数。基本上我有一个表:

create table "SomeData"
(
    ClientId INT,
    SomeData DECIMAL(10,2),
    SomeDate TIMESTAMP
);

有了一些数据:

INSERT INTO "SomeData" (ClientId, SomeData, SomeDate) VALUES
(1, 1, '1 Jan 2000'),
(1, 2, '2 Jan 2000'),
(1, 3, '3 Jan 2000'),
(1, 4, '4 Jan 2000'),
(2, 100, '1 Jan 2000'),
(2, 100, '2 Jan 2000'),
(2, 100, '3 Jan 2000'),
(2, 200, '4 Jan 2000'),
(2, 200, '5 Jan 2000'),
(2, 200, '6 Jan 2000'),
(2, 200, '7 Jan 2000');

我需要一个由 ClientId 分区的运行中位数,按 SomeDate 排序。

基本上,我需要生产的是这样的:

ClientId    SomeDate      Median of SomeData
1           "2000-01-01"  1.000
1           "2000-01-02"  1.500
1           "2000-01-03"  2.000
1           "2000-01-04"  2.500
2           "2000-01-01"  100.0
2           "2000-01-02"  100.0
2           "2000-01-03"  100.0
2           "2000-01-04"  100.0
2           "2000-01-05"  100.0
2           "2000-01-06"  150.0
2           "2000-01-07"  200.0

在PostgresSql 9.x中,我能够以多种方式使用Aggregate_median函数来做到这一点,但是这在Redshift中被证明是困难的,它只有一个聚合的中位数

SELECT ClientId, SomeDate, median(SomeData) OVER (PARTITION BY ClientId ORDER BY SomeDate)
FROM "SomeData" xout
ORDER BY ClientId, SomeDate;

然而,在Redshift上运行上述内容会出现错误:

错误:窗口规范不应包含框架子句和窗口函数中位数的排序依据

中位数可以用手动关联子查询替换回原始表,但 RedShift 似乎也不支持这些。

错误:由于内部错误,不支持此类型的相关子查询模式

这里有一堆在PostGres中工作的小提琴,在Redshift中都不起作用

在这一点上,我似乎需要将数据拉入内存并在代码中执行此操作,但如果可以直接在Redshift中完成此操作,我将不胜感激。

共有3个答案

秦鹏飞
2023-03-14

这是对您要查找的数量的精确计算。

本身并不性感,但它正确地处理了奇数和偶数长度的中间值。

with row_numbers as (
    SELECT d.partitionField -- the field (or fields) you are partitioning the window function by
         , d.orderField  -- your sort field for the window functions
         , d.medianField -- quantity your are computing the median of

         , ROW_NUMBER() 
           OVER (PARTITION BY partitionField ORDER BY orderField) as seqnum

    FROM data d
)

, medians as (    
    SELECT nth_value(medianField, CASE 
                                  WHEN mod(seqnum, 2) = 0 THEN (seqnum/2)::int 
                                  ELSE ((seqnum/2)::int + 1) 
                                  END) 
           OVER (PARTITION BY partitionField ORDER BY orderField ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW) as median1

         , nth_value(medianField, (seqnum/2)::int + 1) OVER (PARTITION BY partitionField ORDER BY orderField ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW) as median2

         , mod(seqnum, 2) as mod1
    FROM row_numbers
    ORDER BY partitionField, orderField
)

select CASE
       when mod(mod1,2) = 0
       then ((median1 + median2)/2)::FLOAT
       else median1
       end as median
from medians
海保臣
2023-03-14

我认为@GordonLinoff提出的解决方案是不正确的,因为它没有对具有您试图寻找的中值的行进行排序。正确的方式受到了启发:

移动中位数,T-SQL 中的模式

工作在红移:

WITH CTE
AS
(
SELECT  ClientId,
        ROW_NUMBER() OVER (PARTITION BY ClientId ORDER BY SomeDate ASC) row_num,
        SomeDate,
        SomeData
FROM "SomeData" 
)
SELECT A.SomeDate,
       A.SomeData,
                (SELECT  MEDIAN(B.SomeData)
                FROM CTE B 
                WHERE B.row_num BETWEEN 1 AND A.row_num 
                GROUP BY A.ClientId) AS median
FROM CTE A
国阳
2023-03-14

我想知道您是否可以使用nth_value()做到这一点:

SELECT ClientId, SomeDate,
       NTH_VALUE(seqnum / 2) OVER (PARTITION BY ClientId ORDER BY SomeDate)
FROM (SELECT s.*,
             COUNT(*) OVER (PARTITION BY ClientId ORDER BY SomeDate) as seqnum
      FROM SomeData s
     ) s
ORDER BY ClientId, SomeDate;

注意:使用< code>COUNT(*)而不是< code>ROW_NUMBER()需要一些时间来适应。

 类似资料:
  • 问题内容: 我想关闭弹出窗口(已知的窗口名称),然后返回到原始窗口。我该怎么办?如果我无法获得窗口中关闭按钮的常量。那么有没有达到目标的一般行为? 问题答案: 你有没有尝试过:

  • 我对流中的事件进行了键控,我希望通过键来累积,直到超时(例如,5分钟),然后处理累积到该点的事件(忽略该键之后的所有内容,但首先是第一件事)。 我是一个新的Flink,但从概念上来说,我认为我需要一些类似下面代码的东西。 如何在Flink中完成键控窗口超时?

  • 我有一个微服务,它会收到一条消息,大概是这样的: 是否有任何开箱即用的解决方案允许方法每天在给定时间运行?使用 Spring 中的 cron 不涉及在运行时更改时间。我需要使用更灵活的选项(更改运行时,多次启动) 谢谢!

  • 本文向大家介绍python移位运算的实现,包括了python移位运算的实现的使用技巧和注意事项,需要的朋友参考一下 密码算法程序设计实践选的SHA-1。 在写的过程中遇到一丢丢关于python移位的问题,记录一下。 SHA-1其中第一步需要填充消息。简单阐述一下sha1填充消息的过程: 如输入消息“123”,先转成ascii码——313233,消息长度为3*8=24。 即00110001 0011

  • 问题内容: 我想做的是从Java应用程序多次运行文件。因此,我设置了一个运行以下代码的时间: 问题是,现在每次运行命令时,都会弹出一个新的cmd窗口。但是,我想要的只是开始时弹出的 一个 窗口,该窗口用于显示以下命令调用中的所有数据。 我怎样才能做到这一点? 问题答案: 使用 & &,您可以执行多个命令,一个接一个地执行: 使用多个命令和条件处理符号 您可以使用条件处理符号从单个命令行或脚本运行多

  • 问题内容: 我有一个3d渲染程序,该程序根据鼠标在屏幕上的位置围绕观察者旋转世界。这条线定义了地球旋转的弧度量 其中xy [0]是屏幕中心的x坐标 这意味着观察者视野的旋转量受到鼠标可以移动的距离的限制。如果我能使鼠标回到屏幕中央,则可以解决此问题。有任何想法吗? 问题答案: 好消息是有一种方法可以做到。 中间的消息是,它没有很好的记录。 坏消息是它仅在某些平台上有效。 另一个中间消息是,您至少可