结合COUNT和RANK-PostgreSQL

时间:2018-08-16 14:09:16

标签: sql postgresql rank

我需要选择的是表用户中每个“ id_customer”及其ID,dispatch_seconds和一次订购距离的总行程数。 id_customer,customer_id和order_id是字符串。

应该看起来像这样

+------+--------+------------+--------------------------+------------------+
|  id  | count  | #1order id | #1order dispatch seconds | #1order distance |
+------+--------+------------+--------------------------+------------------+
| 1ar5 |      3 | 4r56       |                        1 |              500 |
| 2et7 |      2 | dc1f       |                        5 |              100 |
+------+--------+------------+--------------------------+------------------+

干杯!

原文经过编辑,因为在讨论过程中S-man帮助我找到了确切的问题解决方案。 S-man https://dbfiddle.uk/?rdbms=postgres_10&fiddle=e16aa6008990107e55a26d05b10b02b5

解决方案

4 个答案:

答案 0 :(得分:1)

db<>fiddle

SELECT 
    customer_id,
    order_id,
    order_timestamp,
    dispatch_seconds,
    distance
FROM (
    SELECT 
        *, 
        count(*) over (partition by customer_id),    -- A
        first_value(order_id) over (partition by customer_id order by order_timestamp) -- B
    FROM orders
)s

WHERE order_id = first_value -- C

https://www.postgresql.org/docs/current/static/tutorial-window.html

一个窗口功能,可获取每个用户的总记录数

B窗口函数,该函数按时间戳对每个用户的所有记录进行排序,并给出相应用户的第一个order_id。使用first_value而不是min有一个好处:也许您的订单ID并没有按时间戳实际增加(也许两个订单同时进入,或者您的订单ID并不是按顺序增加,而是某种形式)哈希)

->都是新列

C现在获得所有列,其中“ first_value”(按时间戳记即第一个order_id)等于当前行的order_id。这将按用户给出所有具有第一顺序的行。

结果:

customer_id  count  order_id  order_timestamp      dispatch_seconds  distance  
-----------  -----  --------  -------------------  ----------------  --------  
1ar5         3      4r56      2018-08-16 17:24:00  1                 500       
2et7         2      dc1f      2018-08-15 01:24:00  5                 100   

请注意,在这些测试数据中,用户“ 2et7”的顺序“ dc1f”具有较小的时间戳,但排在后面。它不是表中用户的第一个出现,而是顺序最早的用户。如上所述,这应该证明first_valuemin的对比。

答案 1 :(得分:0)

您可以使用窗口功能:

select distinct customer_id, 
       count(*) over (partition by customer_id) as no_of_order
       min(order_id) over (partition by customer_id order by order_timestamp) as first_order_id
from orders o;

答案 2 :(得分:0)

我认为您的原始查询中有很多错误,您的排名未分区,order by子句似乎不正确,您仅过滤了一个“随机”订单,然后应用计数,列表继续。 / p>

这样的事情似乎更接近您想要的东西?

SELECT
    customer_id,
    order_count,
    order_id
FROM (
    SELECT
        a.customer_id,
        a.order_count,
        a.order_id,
        RANK() OVER (PARTITION BY a.order_id, a.customer_id ORDER BY a.order_count DESC) AS rank_id
    FROM (
        SELECT
            customer_id,
            order_id,
            COUNT(*) AS order_count
        FROM 
            orders
        GROUP BY
            customer_id,
            order_id) a) b
WHERE 
    b.rank_id = 1;

答案 3 :(得分:0)

您处在正确的轨道上。只需使用条件聚合:

SELECT o.customer_id, COUNT(*)
       MAX(CASE WHEN seqnum = 1 THEN o.order_id END) as first_order_id
FROM (SELECT o.*,
             ROW_NUMBER() OVER (PARTITION BY customer_id ORDER BY order_timestamp ASC) as seqnum
      FROM orders o
     ) o
GROUP BY o.customer_id;

您的JOIN对于此查询不是必需的。