PAS
PAS

Reputation: 89

Interview question:How to get last 3 month aggregation at column level?

This is the question i was being asked at Apple onsite interview and it blew my mind. Data is like this:

orderdate,unit_of_phone_sale

20190806,3000

20190704,3789

20190627,789

20190503,666

20190402,765

I had to write a query to get the result for each month sale, we should have last 3 month sales values. Let me put the expected output here.

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

I could only got the month wise sale and and used case statement by hardcoding month which was wrong. I banged my head to write this sql, but i could not.

Can anyone help on this. It will be really helpful for me to prepare for sql interviews

Update: This is what i tried

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

Upvotes: 1

Views: 192

Answers (3)

Popeye
Popeye

Reputation: 35910

You will first of all need to sum the month's data and then use the LAG function to get previous months' data as following:

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;

Output:

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

Cheers!!

-- Update --

For the requirement mentioned in the comments, Following query will work for it.

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

Output:

enter image description here

db<>fiddle demo of updated answer.

Cheers!!

Upvotes: 2

Isuri Subasinghe
Isuri Subasinghe

Reputation: 147

You can use this query:

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

Output

Upvotes: 0

Ankit Bajpai
Ankit Bajpai

Reputation: 13509

I think LEAD function can help here -

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

Here is the DB Fiddle

Upvotes: 0

Related Questions