【问题标题】:Grouping records on consecutive dates对连续日期的记录进行分组
【发布时间】:2017-09-22 12:15:51
【问题描述】:

如果我在 Postgres 中有下表:

order_dtls

Order_id    Order_date  Customer_name
-------------------------------------
1           11/09/17    Xyz
2           15/09/17    Lmn
3           12/09/17    Xyz
4           18/09/17    Abc
5           15/09/17    Xyz
6           25/09/17    Lmn
7           19/09/17    Abc

我想检索连续两天下订单的客户。 在上述情况下,XyzAbc 客户应通过查询作为结果返回。

【问题讨论】:

  • 你使用的是 MySQL 还是 Postgresql?
  • 那么您的实际问题是什么?你试过什么?你被困在哪里了?
  • 我正在使用 Postgresql,我的问题是如何在连续的 2 个日期上应用 group by 子句
  • 您的最后一条评论使要求不太清楚 - 如果您可以扩展您的示例数据以说明分组依据的含义以及如果客户在 3,4(etc) 上有事件会发生什么情况,这可能会有所帮助连续几天。

标签: sql postgresql aggregate gaps-and-islands


【解决方案1】:

有很多方法可以做到这一点。使用EXISTS 半连接,后跟DISTINCTGROUP BY,应该是最快的。

Postgres 语法:

SELECT DISTINCT customer_name
FROM   order_dtls o
WHERE  EXISTS (
   SELEST 1 FROM order_dtls
   WHERE  customer_name = o.customer_name
   AND    order_date = o.order_date + 1  -- simple syntax for data type "date" in Postgres!
   );

如果表很大,请确保在(customer_name, order_date) 上有一个索引以使其快速 - 按此顺序索引项目。

澄清一下,因为 Oto 恰好发帖 almost the same solution 快一点:

DISTINCT 是一个 SQL 结构,一个语法元素,而不是一个函数。请不要使用DISTINCT (customer_name)之类的括号。将是 DISTINCT ROW(customer_name) 的缩写 - 与 DISTINCT 无关的行构造函数 - 对于具有单个表达式的简单案例来说只是噪音,因为 Postgres 会自动删除单个元素的无意义行包装器。但是如果你像这样包装多个表达式,你会得到一个实际的行类型——实际上是一个匿名记录,因为没有给出行类型。肯定不是你想要的。

另外,不要将DISTINCTDISTINCT ON (expr, ...) 混淆。见:

【讨论】:

    【解决方案2】:

    尝试类似...

    SELECT `order_dtls`.*
    FROM `order_dtls`
    INNER JOIN `order_dtls` AS mirror
    ON `order_dtls`.`Order_id` <> `mirror`.`Order_id`
    AND `order_dtls`.`Customer_name` = `mirror`.`Customer_name`
    AND DATEDIFF(`order_dtls`.`Order_date`, `mirror`.`Order_date`) = 1
    

    【讨论】:

      【解决方案3】:

      我认为这样做的方式是在下一个日期将日期部分与 selft 连接起来,并将其与 Customer_name 连接起来。 这样可以确保连续 2 天同一个 customer_name 下单。

      对于 MySQL:

      SELECT distinct *
      FROM order_dtls t1
          INNER JOIN order_dtls t2 on
                  t1.Order_date = DATE_ADD(t2.Order_date, INTERVAL 1 DAY) and
                  t1.Customer_name = t2.Customer_name
      

      您还应该使用 Distinct 关键字选择结果,以确保同一客户不会显示超过 1 次。

      【讨论】:

      • mysql 和 postgresql 都没有 dateadd 函数。 Mysql 语法将是 DATE_ADD(t2.Order_date, interval 1 day) 在这种情况下,解决方案会产生预期的结果。
      • 你完全正确。我将修改答案以包含 MySQL
      【解决方案4】:

      对于 postgresql:

      select distinct(Customer_name) from your_table
      where exists 
          (select 1 from your_table t1 
          where 
          Customer_name = your_table.Customer_name and Order_date = your_table.Order_date+1 )
      

      对于 MySQL 也是如此,只是使用 your_table.Order_date+1 代替 DATE_ADD(your_table.Order_date , INTERVAL 1 DAY)

      【讨论】:

        【解决方案5】:

        这应该可行:

        SELECT A.customer_name
            FROM order_dtls A
            INNER JOIN (SELECT customer_name, order_date FROM order_dtls) as B
            ON(A.customer_name = B.customer_name and Datediff(B.Order_date, A.Order_date) =1)
            group by A.customer_name
        

        【讨论】:

        • Datediff(B.order,A.order) 应该是 Datediff(B.order_date,A.order_date)
        猜你喜欢
        • 2021-12-05
        • 1970-01-01
        • 2020-05-23
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2018-07-22
        相关资源
        最近更新 更多