SELECT
mem_jan AS num_of_mems_shopped_january21,
mem_feb AS retained_february21,
mem_feb / mem_jan * 100 as 1month_retention_rate
mem_3m / mem_jan * 100 as within_3months
FROM(
SELECT
SUM(IF(mm_jan>0,1,0) AS mem_jan,
SUM(IF(mm_jan>0 AND mm_feb>0,1,0) AS mem_feb,
SUM(IF(mm_jan>0 AND mm_count_3m>0,1,0) AS mem_3m
FROM
(
SELECT
t.Id,
SUM(IF(year_month = 202101, 1,0)) AS mm_jan, /*visit for a member in Jan*/
SUM(IF(year_month = 202102, 1,0)) AS mm_feb, /*visit for a member in Feb*/
SUM(IF(year_month between 202102 and 202104,1,0)) AS mem_3m/*visit for a member in 3 months*/
FROM
table.members t
join table.date tm on t.dt_key = tm.date_key
WHERE
year_month between 202101 and 202104
GROUP BY
t.Id
) AS t1
) AS t2
SELECT 202101 AS year_month,
COUNT(CASE WHEN cnt_202101 > 0 THEN 1 END)
AS members_shopped_202101,
COUNT(CASE WHEN cnt_202101 > 0 AND cnt_202102 > 0 THEN 1 END)
AS members_retained_202102,
COUNT(CASE WHEN cnt_202101 > 0 AND cnt_202102 > 0 THEN 1 END)
/ COUNT(CASE WHEN cnt_202101 > 0 THEN 1 END) * 100
AS one_month_retention_rate,
COUNT(CASE WHEN cnt_202101 > 0 AND (cnt_202102 > 0 OR cnt_202103 > 0 OR cnt_202104 > 0) THEN 1 END)
/ COUNT(CASE WHEN cnt_202101 > 0 THEN 1 END) * 100
AS within_3months
FROM (
SELECT members,
year_month
FROM members m
INNER JOIN date d
ON m.dt_key = d.date_key
)
PIVOT (
COUNT(*)
FOR year_month IN (
202101 AS cnt_202101,
202102 AS cnt_202102,
202103 AS cnt_202103,
202104 AS cnt_202104
)
);
3条答案
按热度按时间jv2fixgn1#
错误不是来自添加的左连接,而是来自
as 1month_retention_rate
部分,因为它是非法名称。您可以通过以下方式更简单地了解这一点:
ORA-00923:在预期位置未找到FROM关键字
您可以更改列别名,使其遵循命名规则(特别是在这里,不以数字开头),或者如果确实需要该特定名称,则可以将其设置为带引号的标识符-通常不是一个好选项,但有时在查询的最终输出中也是可以的。
fiddle
所以在代码中,你只需更改新行
变成了
或使用带引号的标识符
fiddle-仍有错误,但现在使用ORA-00942,因为我没有您的表,而且这是在将您的模糊模式/表名更改为合法名称之后。
可能有更有效的方法来执行计算,但这是一个单独的问题...
8cdiaqws2#
我能理解你想得到:
如果我的理解是正确的,那么您可以使用IF而不是LEFT JOIN来简化内部查询。请看下面的查询。假设表成员有一个ID字段:
这不是一个最终运行的查询,但它可以解释我的想法。
sqxo8psd3#
不要使用多个联接,计算每个成员每月的商店数,然后使用条件聚合。
在Oracle中,这将是: