列值的SQL总和,每个用户每天唯一

时间:2013-01-11 21:12:42

标签: sql ruby-on-rails postgresql

我有一个看起来像这样的postgres表:

id | user_id | state | created_at

州可以是以下任何一种:

new, paying, paid, completing, complete, payment_failed, completion_failed

我需要一个声明,该声明返回一个包含以下内容的报告:

  1. 按日期列出的所有付费州的总和
  2. 按日期填写的所有州的总和
  3. 按日期计算的所有新的,付费的,完成状态的总和,每个用户每天只计算一个
  4. 所有payment_failed的总和,completion_failed按日期计算,每位用户每天只计算一次
  5. 到目前为止,我有这个:

    SELECT
      DATE(created_at) AS date,
      SUM(CASE WHEN state = 'complete' THEN 1 ELSE 0 END) AS complete,
      SUM(CASE WHEN state = 'paid' THEN 1 ELSE 0 END) AS paid
    FROM orders
    WHERE created_at BETWEEN ? AND ?
    GROUP BY DATE(created_at)
    

    通过将其添加到select:

    ,可以很容易地处理正在进行和失败的状态
    SUM(CASE WHEN state IN('new','paying','completing') THEN 1 ELSE 0 END) AS in_progress,
    SUM(CASE WHEN state IN('payment_failed','completion_failed') THEN 1 ELSE 0 END) AS failed 
    

    但是我无法弄清楚如何每天每个user_id只进行一次in_progress和失败的状态计算。

    我需要这个的原因是操纵我们的统计数据中的失败率,因为许多触发失败或不完整订单的用户继续触发更多会导致我们失败率的事件。

    提前感谢你。

2 个答案:

答案 0 :(得分:3)

SELECT created_at::date AS the_date
      ,SUM(CASE WHEN state = 'complete' THEN 1 ELSE 0 END) AS complete
      ,SUM(CASE WHEN state = 'paid' THEN 1 ELSE 0 END) AS paid
      ,COUNT(DISTINCT CASE WHEN state IN('new','paying','completing')
                      THEN user_id ELSE NULL END) AS in_progress
      ,COUNT(DISTINCT CASE WHEN state IN('payment_failed','completion_failed')
                      THEN user_id ELSE NULL END) AS failed 
FROM   orders
WHERE  created_at BETWEEN ? AND ?
GROUP  BY created_at::date

我使用the_date作为别名,因为使用关键字日期作为标识符是不明智的(虽然允许)。

您可以对completepaid使用类似的技巧,其中一种技巧与其他技术一样好:

COUNT(CASE WHEN state = 'complete' THEN 1 ELSE NULL END) AS complete

答案 1 :(得分:2)

尝试类似:

SELECT
  DATE(created_at) AS date,
  SUM(CASE WHEN state = 'complete' THEN 1 ELSE 0 END) AS complete,
  SUM(CASE WHEN state = 'paid' THEN 1 ELSE 0 END) AS paid,
  COUNT(DISTINCT CASE WHEN state IN('new','paying','completing') THEN user_id ELSE NULL END) AS in_progress,
  COUNT(DISTINCT CASE WHEN state IN('payment_failed','completion_failed') THEN user_id ELSE NULL END) AS failed
FROM orders
WHERE created_at BETWEEN ? AND ?
GROUP BY DATE(created_at);

主要想法 - COUNT (DISTINCT ...)将统计唯一user_id并且不会计算NULL值。

详细信息:aggregate functions4.2.7. Aggregate Expressions

具有相同样式的整个查询计数并简化为CASE WHEN ...

SELECT
  DATE(created_at) AS date,
  COUNT(CASE WHEN state = 'complete' THEN 1 END) AS complete,
  COUNT(CASE WHEN state = 'paid' THEN 1 END) AS paid,
  COUNT(DISTINCT CASE WHEN state IN('new','paying','completing') THEN user_id END) AS in_progress,
  COUNT(DISTINCT CASE WHEN state IN('payment_failed','completion_failed') THEN user_id END) AS failed
FROM orders
WHERE created_at BETWEEN ? AND ?
GROUP BY DATE(created_at);