0

如何找到已付款的卖家数量,连续时间小于 1 分钟以及连续执行至少 3 次的时间?(答案是 2 个卖家)以及如何计算此类付款的数量?(答案是10块钱)好像这样的问题可以用窗口函数解决,但是我从来没有遇到过这种问题

在此处输入图像描述

CREATE TABLE T (seller_id int, payment_id varchar(3), payment_time timestamp, second_diff int);
    
INSERT INTO T (seller_id, payment_id, payment_time, second_diff)
VALUES
    (1, 'pl',  '2015-01-08 09:23:04', 151),
    (1, 'p2',  '2015-01-08 09:25:35', 50),
    (1, 'p3',  '2015-01-08 09:26:25', 48),
    (1, 'p4',  '2015-01-08 09:27:23', 36),
    (1, 'p5',  '2015-01-08 09:27:59', 41),
    (1, 'p6',  '2015-01-08 09:28:40', 70),
    (1, 'p7',  '2015-01-08 09:29:50', 50),
    (1, 'p8',  '2015-01-08 09:30:40', 45),
    (1, 'p9',  '2015-01-08 09:31:25', 35),
    (1, 'p10', '2015-01-08 09:32:00', null),
    (2, 'pll', '2015-01-08 09:25:35', 25),
    (2, 'p12', '2015-01-08 09:26:00', 55),
    (2, 'p13', '2015-01-08 09:26:55', 30),
    (2, 'p14', '2015-01-08 09:27:25', 95),
    (2, 'p15', '2015-01-08 09:29:00', null),
    (3, 'p16', '2015-01-08 10:41:00', 65),
    (3, 'p17', '2015-01-08 10:42:05', 75),
    (3, 'p18', '2015-01-08 10:43:20', 90),
    (3, 'p19', '2015-01-08 10:43:20', 39),
    (3, 'p20', '2015-01-08 10:43:59', 50),
    (3, 'p21', '2015-01-08 10:44:49', null);
4

2 回答 2

1
with A as (
    select seller_id, payment_time, second_diff,
        case when
            lag(case when second_diff < 60 then 1 else 0 end)
                over (partition by seller_id order by payment_time)
              = case when second_diff < 60 then 1 else 0 end
            then 0 else 1 end as transition
    from T
), B as (
    select *,
        sum(transition)
            over (partition by seller_id order by payment_time) as grp
    from A
), C as (
    select seller_id, count(*) as p
    from B
    where second_diff < 60
    group by seller_id, grp
    having count(*) >= 3
) 
select count(distinct seller_id) as sellers, sum(p) as payments
from C;

这种方法在值中查找转换,并将它们计数。只要它们匹配,内部表达式的输出值case并不重要。

https://dbfiddle.uk/?rdbms=postgres_9.6&fiddle=606b796d793248336a95637f02ce117b

以下是主题的一些变化:

选项#1b:

with A as (
    select seller_id, payment_time, second_diff,
        case when
            lag(case when second_diff < 60 then 1 else 0 end)
                over (partition by seller_id order by payment_time)
              = case when second_diff < 60 then 1 else 0 end
            then 0 else 1 end as transition
    from T
), B as (
    select *,
        sum(transition)
            over (partition by seller_id order by payment_time) as grp
    from A
)
select
    dense_rank() over (order by seller_id)
      + dense_rank() over (order by seller_id desc) - 1 as sellers,
    sum(count(*)) over () as payments
from B
where second_diff < 60
group by seller_id, grp
having count(*) >= 3
limit 1;

这只是count(distinct)一步完成的另一种方式。

选项#2:

with A as (
    select seller_id, payment_time, second_diff,
        row_number() over (partition by seller_id order by payment_time) as rn
    from T
), B as (
    select *,
        rn - row_number() over (partition by seller_id order by payment_time) as grp
    from A
    where second_diff < 60    
), C as (
    select seller_id, count(*) as p
    from B
    group by seller_id, grp
    having count(*) >= 3
) 
select count(distinct seller_id) as sellers, sum(p) as payments
from C;

此方法使用筛选前后的行编号来查找系列中的中断。

于 2021-11-16T15:30:20.203 回答
0

使用带有 OVER 子句的聚合函数,其中包含整数除以 60,然后在此除法上过滤结果 0

WITH T AS
(
SELECT ... COUNT(*) OVER(PARTITION BY second_diff / 60) AS CNT, second_diff / 60 AS GRP
FROM ....
) 
SELECT * FROM T
WHERE GRP = 0
于 2021-11-16T15:20:52.873 回答