面试题:如何在列级别获得最近3个月的聚合?
Posted
技术标签:
【中文标题】面试题:如何在列级别获得最近3个月的聚合?【英文标题】:Interview question:How to get last 3 month aggregation at column level? 【发布时间】:2019-08-07 05:01:41 【问题描述】:这是我在 Apple 现场采访中被问到的问题,让我大吃一惊。数据是这样的:
orderdate,unit_of_phone_sale
20190806,3000
20190704,3789
20190627,789
20190503,666
20190402,765
我必须编写一个查询来获取每个月销售的结果,我们应该有最近 3 个月的销售值。让我把预期的输出放在这里。
order_monnth,M-1_Sale, M-2_Sale, M-3_Sale
201908,3000,3789,789,666
201907,3789,789,666,765
201906,789,666,765,0
201905,666,765,0,0
201904,765,0,0
我只能通过硬编码月份获得明智的销售和使用案例陈述,这是错误的。我敲了敲头想写这个sql,但我写不出来。
任何人都可以帮助解决这个问题。对我准备sql面试真的很有帮助
更新:这是我尝试过的
with abc as(
select to_char(order_date,'YYYYMM') as yearmonth,to_char(order_date,'YYYY') as year,to_char(order_date,'MM') as moth, sum(unit_of_phone_sale) as unit_sale
from t1 group by to_char(order_date,'YYYYMM'),to_char(order_date,'YYYY'),to_char(order_date,'MM'))
select yearmonth, year, case when month=01 then unit_sale else 0 end as M1_Sale,
case when month=02 then unit_sale else 0 end as M2_Sale...
case when month=12 then unit_sale else 0 end as M12_Sale
from abc
【问题讨论】:
在 Apple 的一次采访中,您被问到一个 Oracle 问题?这真的是预期的输出吗?我认为这太复杂了,无法在一分钟内快速回答。 第一个回复应该是:“永远不要将 date 值存储为字符串或数字 - 使用正确的DATE
或 TIMESTAMP
数据类型。”
【参考方案1】:
您首先需要对当月的数据求和,然后使用 LAG 函数获取前几个月的数据,如下所示:
SELECT
ORDER_MONTH,
LAG(UNIT_OF_PHONE_SALE, 1) OVER(
ORDER BY
ORDER_MONTH
) AS "M-1_Sale",
LAG(UNIT_OF_PHONE_SALE, 2) OVER(
ORDER BY
ORDER_MONTH
) AS "M-2_Sale",
LAG(UNIT_OF_PHONE_SALE, 3) OVER(
ORDER BY
ORDER_MONTH
) AS "M-3_Sale"
FROM
(
SELECT
TO_CHAR(ORDERDATE, 'YYYYMM') AS ORDER_MONTH,
SUM(UNIT_OF_PHONE_SALE) AS UNIT_OF_PHONE_SALE
FROM
DATAA
GROUP BY
TO_CHAR(ORDERDATE, 'YYYYMM')
)
ORDER BY
ORDER_MONTH DESC;
输出:
ORDER_ M-1_Sale M-2_Sale M-3_Sale
------ ---------- ---------- ----------
201908 3789 789 666
201907 789 666 765
201906 666 765
201905 765
201904
db<>fiddle demo
干杯!!
-- 更新--
对于 cmets 中提到的要求,以下查询将适用。
CTE AS (
SELECT
TRUNC(ORDERDATE, 'MONTH') AS ORDER_MONTH,
SUM(UNIT_OF_PHONE_SALE) AS UNIT_OF_PHONE_SALE
FROM
DATAA
GROUP BY
TRUNC(ORDERDATE, 'MONTH')
)
SELECT
TO_CHAR(C.ORDER_MONTH,'YYYYMM') as ORDER_MONTH,
NVL(C1.UNIT_OF_PHONE_SALE, 0) AS "M-1_Sale",
NVL(C2.UNIT_OF_PHONE_SALE, 0) AS "M-2_Sale",
NVL(C3.UNIT_OF_PHONE_SALE, 0) AS "M-3_Sale"
FROM
CTE C
LEFT JOIN CTE C1 ON ( C1.ORDER_MONTH = ADD_MONTHS(C.ORDER_MONTH, - 1) )
LEFT JOIN CTE C2 ON ( C2.ORDER_MONTH = ADD_MONTHS(C.ORDER_MONTH, - 2) )
LEFT JOIN CTE C3 ON ( C3.ORDER_MONTH = ADD_MONTHS(C.ORDER_MONTH, - 3) )
ORDER BY
C.ORDER_MONTH DESC
输出:
db<>fiddle demo 的更新答案。
干杯!!
【讨论】:
这是完美的 如果 201907 数据丢失怎么办,第一个记录将在 6 月作为 M-2。知道如何解决它 您是否在上述情况下尝试过此查询?它的工作方式与您的预期完全相同? 对不起,误会了。您的确切期望是什么? 所以如果数据丢失一个月,它应该是 null 。例如,对于 201907 没有数据,那么 201908 行 m_1_sale 应该为 0。请您帮忙【参考方案2】:我认为 LEAD 功能在这里可以提供帮助 -
SELECT TO_CHAR(orderdate, 'YYYYMM') "DATE"
,unit_of_phone_sale M_1_Sale
,LEAD(unit_of_phone_sale,1,0) OVER(ORDER BY TO_CHAR(orderdate, 'YYYYMM') DESC) M_2_Sale
,LEAD(unit_of_phone_sale,2,0) OVER(ORDER BY TO_CHAR(orderdate, 'YYYYMM') DESC) M_3_Sale
,LEAD(unit_of_phone_sale,3,0) OVER(ORDER BY TO_CHAR(orderdate, 'YYYYMM') DESC) M_4_Sale
FROM table_sales
这里是DB Fiddle
【讨论】:
【参考方案3】:你可以使用这个查询:
select a.order_month, a.unit_of_phone_sale,
LEAD(unit_of_phone_sale, 1, 0) OVER (ORDER BY rownum) AS M_1,
LEAD(unit_of_phone_sale, 2, 0) OVER (ORDER BY rownum) AS M_2,
LEAD(unit_of_phone_sale, 3, 0) OVER (ORDER BY rownum) AS M_3
from (
select TO_CHAR(orderdate, 'YYYYMM') order_month,
unit_of_phone_sale,
rownum
from Y
order by order_month desc) a
【讨论】:
以上是关于面试题:如何在列级别获得最近3个月的聚合?的主要内容,如果未能解决你的问题,请参考以下文章
如何使用月份名称获取最近 3 个月的计数,如果该月份没有记录需要使用月份名称获取 0 [重复]
如何从当前日期 PHP 获取最近 7 周、7 个月的日期范围?