我有一个看起来像这样的postgres表:
id | user_id | state | created_at
州可以是以下任何一种:
new, paying, paid, completing, complete, payment_failed, completion_failed
我需要一个声明,该声明返回一个包含以下内容的报告:
到目前为止,我有这个:
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和失败的状态计算。
我需要这个的原因是操纵我们的统计数据中的失败率,因为许多触发失败或不完整订单的用户继续触发更多会导致我们失败率的事件。
提前感谢你。
答案 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
作为别名,因为使用关键字日期作为标识符是不明智的(虽然允许)。
您可以对complete
和paid
使用类似的技巧,其中一种技巧与其他技术一样好:
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 functions,4.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);