I have two tables, one that contains production data and the other has forecasted data. I am joining the two tables to compare the actual production data to forecasted data.
My sample tables are as follows:
**Prod Tbl**
Product Plant pmonth pyear quantity
B007 2 January 2014 45
B007 2 February 2014 270
B007 2 March 2014 270
B007 2 April 2014 45
B007 2 May 2014 90
B007 2 May 2014 90
B007 2 June 2014 90
B007 2 June 2014 90
B007 2 July 2014 135
B007 2 July 2014 45
B007 2 August 2014 135
B007 2 August 2014 135
B007 2 July 2015 90
B007 2 August 2014 135
B007 2 September 2014 135
B007 2 September 2015 135
B007 2 October 2015 90
B007 2 September 2014 135
B007 2 September 2014 90
B007 2 September 2014 90
B007 2 November 2014 254
B007 2 May 2016 90
B007 2 August 2016 135
B007 2 October 2016 87
**Forecast Tbl**
Product Plant Fmonth Fyear Fqty
B007 2 July 2017 100
B007 2 August 2017 100
B007 2 September 2017 100
B007 2 October 2017 100
B007 2 Novenmber 2017 100
B007 2 December 2017 100
Query Used to Join:
Select a.Product,
a.plant,
b.pmonth,
b.pyear,
coalesce(b.quantity,0) as quantity,
a.fmonth,
a.fyear,coalesce(a.fqty,0) as fqty
from
Frcast_Tbl as a
left join on Prod_Tbl as b on (a.Product = b.Product
and a.Plant = b.plant
and b.pMonth = a.fMonth);
Result:
After Joining
Product Plant Pmonth Pyear Quantity Fmonth Fyear fqty
B007 2 July 2014 180 July 2017 100
B007 2 July 2015 90 July 2017 100
B007 2 August 2014 405 August 2017 100
B007 2 August 2016 315 August 2017 100
B007 2 September 2014 450 September 2017 100
B007 2 September 2015 135 September 2017 100
B007 2 October 2016 177 October 2017 100
B007 2 October 2015 90 October 2017 100
B007 2 November 2014 356 November 2017 100
B007 2 December 2016 90 December 2017 100
B007 2 January 2015 90 January 2018 100
B007 2 January 2016 90 January 2018 100
B007 2 January 2014 45 January 2018 100
B007 2 January 2017 90 January 2018 100
B007 2 February 2014 270 February 2018 99
B007 2 March 2014 270 March 2018 101
B007 2 March 2017 90 March 2018 101
B007 2 April 2014 45 April 2018 100
B007 2 May 2016 90 May 2018 100
B007 2 May 2014 180 May 2018 100
B007 2 May 2017 90 May 2018 100
Filtered for a particular year to better explain the problem
Producr plant pmonth pyear quantity fmonth fyear fqty
B007 2 August 2016 315 August 2017 100
B007 2 October 2016 177 October 2017 100
B007 2 December 2016 90 December 2017 100
Desired Table
Product Plant Pmonth Pyear Quantity fmonth fyear fqty
B007 2 January 2016 90 null null 0
B007 2 May 2016 90 null null 0
B007 2 June 2016 270 null null 0
B007 2 null null 0 July 2017 100
B007 2 August 2016 315 August 2017 100
B007 2 null null 0 September 2017 100
B007 2 October 2016 177 October 2017 100
B007 2 null null 0 November 2017 100
B007 2 December 2016 90 December 2017 100
What my query is doing is that it joins item, plant and month using left join but I want my resultant table to display all the months for both prod and frcast and in cases where month is not found, display null or zeros. Please help.
You could try this. The Subquery after FULL JOIN is to extract only one year from Products table.
I added a CASE for ORDER BY too.
One year version
SELECT COALESCE(a.Product,b.Product) AS PRODUCT,
COALESCE(a.plant,b.plant) AS PLANT,
b.pmonth,
b.pyear,
coalesce(b.quantity,0) as quantity,
a.fmonth AS FMONTH,
a.fyear,
coalesce(a.fqty,0) as fqty
FROM FORECAST A
FULL JOIN (SELECT * FROM PROD WHERE pyear=2016) B on a.Product = b.Product
and a.Plant = b.plant
and A.fmonth = b.pMonth
ORDER BY CASE COALESCE(b.pmonth, a.fmonth)
WHEN 'January' THEN 1
WHEN 'February' THEN 2
WHEN 'March' THEN 3
WHEN 'April' THEN 4
WHEN 'May' THEN 5
WHEN 'June' THEN 6
WHEN 'July' THEN 7
WHEN 'August' THEN 8
WHEN 'September' THEN 9
WHEN 'October' THEN 10
WHEN 'November' THEN 11
WHEN 'December' THEN 12
END ;
Pls note that your sample data (first table) are not complete.
Output:
+-------------+-------+---------+-------+----------+-----------+-------+------+
| PRODUCT | PLANT | pmonth | pyear | quantity | FMONTH | fyear | fqty |
+-------------+-------+---------+-------+----------+-----------+-------+------+
| B007 | 2 | January | 2016 | 90 | NULL | NULL | 0 |
| B007 | 2 | May | 2016 | 90 | NULL | NULL | 0 |
| B007 | 2 | June | 2016 | 270 | NULL | NULL | 0 |
| B007 | 2 | NULL | NULL | 0 | July | 2017 | 100 |
| B007 | 2 | August | 2016 | 135 | August | 2017 | 100 |
| B007 | 2 | NULL | NULL | 0 | September | 2017 | 100 |
| B007 | 2 | October | 2016 | 87 | October | 2017 | 100 |
| B007 | 2 | NULL | NULL | 0 | November | 2017 | 100 |
| B007 | 2 | NULL | NULL | 0 | December | 2017 | 100 |
+-------------+-------+---------+-------+----------+-----------+-------+------+
Added: multi year version, with group by on PROD table
SELECT COALESCE(a.Product,b.Product) AS PRODUCT,
COALESCE(a.plant,b.plant) AS PLANT,
b.pmonth,
COALESCE(b.pyear,Y.pyear) AS pyear,
COALESCE(b.quantity,0) as quantity,
a.fmonth AS FMONTH,
a.fyear,
coalesce(a.fqty,0) as fqty
FROM FORECAST A
CROSS JOIN (SELECT DISTINCT pyear FROM PROD /* WHERE pyear IN (2015,2016)*/ ) Y
FULL JOIN (SELECT Product, Plant, pyear, pmonth, SUM(quantity) AS quantity
FROM PROD /*WHERE pyear IN (2015,2016)*/
GROUP BY Product, Plant, pyear, pmonth
) B on a.Product = b.Product
and a.Plant = b.plant
and A.fmonth = b.pMonth
AND Y.pyear= B.pyear
ORDER BY COALESCE(b.pyear,Y.pyear), CASE COALESCE(b.pmonth, a.fmonth)
WHEN 'January' THEN 1
WHEN 'February' THEN 2
WHEN 'March' THEN 3
WHEN 'April' THEN 4
WHEN 'May' THEN 5
WHEN 'June' THEN 6
WHEN 'July' THEN 7
WHEN 'August' THEN 8
WHEN 'September' THEN 9
WHEN 'October' THEN 10
WHEN 'November' THEN 11
WHEN 'December' THEN 12
END ;
Output:
+---------+-------+-----------+-------+----------+-----------+-------+------+
| PRODUCT | PLANT | pmonth | pyear | quantity | FMONTH | fyear | fqty |
+---------+-------+-----------+-------+----------+-----------+-------+------+
| B007 | 2 | January | 2014 | 45 | NULL | NULL | 0 |
| B007 | 2 | February | 2014 | 270 | NULL | NULL | 0 |
| B007 | 2 | March | 2014 | 270 | NULL | NULL | 0 |
| B007 | 2 | April | 2014 | 45 | NULL | NULL | 0 |
| B007 | 2 | May | 2014 | 180 | NULL | NULL | 0 |
| B007 | 2 | June | 2014 | 180 | NULL | NULL | 0 |
| B007 | 2 | July | 2014 | 180 | July | 2017 | 100 |
| B007 | 2 | August | 2014 | 405 | August | 2017 | 100 |
| B007 | 2 | September | 2014 | 450 | September | 2017 | 100 |
| B007 | 2 | NULL | 2014 | 0 | October | 2017 | 100 |
| B007 | 2 | November | 2014 | 254 | November | 2017 | 100 |
| B007 | 2 | NULL | 2014 | 0 | December | 2017 | 100 |
| B007 | 2 | July | 2015 | 90 | July | 2017 | 100 |
| B007 | 2 | NULL | 2015 | 0 | August | 2017 | 100 |
| B007 | 2 | September | 2015 | 135 | September | 2017 | 100 |
| B007 | 2 | October | 2015 | 90 | October | 2017 | 100 |
| B007 | 2 | NULL | 2015 | 0 | November | 2017 | 100 |
| B007 | 2 | NULL | 2015 | 0 | December | 2017 | 100 |
| B007 | 2 | January | 2016 | 90 | NULL | NULL | 0 |
| B007 | 2 | May | 2016 | 90 | NULL | NULL | 0 |
| B007 | 2 | June | 2016 | 270 | NULL | NULL | 0 |
| B007 | 2 | NULL | 2016 | 0 | July | 2017 | 100 |
| B007 | 2 | August | 2016 | 135 | August | 2017 | 100 |
| B007 | 2 | NULL | 2016 | 0 | September | 2017 | 100 |
| B007 | 2 | October | 2016 | 87 | October | 2017 | 100 |
| B007 | 2 | NULL | 2016 | 0 | November | 2017 | 100 |
| B007 | 2 | NULL | 2016 | 0 | December | 2017 | 100 |
+---------+-------+-----------+-------+----------+-----------+-------+------+
Use FULL OUTER JOIN when you are filtering records for specific year
Select a.Product,a.plant,b.pmonth,b.pyear,coalesce(b.quantity,0) as quantity,a.fmonth,a.fyear,coalesce(a.fqty,0) as fqty
from Frcast_Tbl as a
FULL OUTER JOIN on Prod_Tbl as b on a.Product = b.Product and
a.Plant = b.plant and
b.pMonth = a.fMonth
Related
I divided the month into four weeks and printed the amount for each week. How do I set this up with a loop for 12 months?
declare
cursor c is
select varis_tar, tutar
from muhasebe.doviz_takip
where trunc(varis_tar) BETWEEN TO_DATE('01/10/2021', 'DD/MM/YYYY') AND
TO_DATE('31/10/2021', 'DD/MM/YYYY')
group by varis_tar,tutar;
tutar1 number(13,2):=0;
tutar2 number(13,2):=0;
tutar3 number(13,2):=0;
tutar4 number(13,2):=0;
begin
for r in c loop
if r.varis_tar between TO_DATE('01/10/2021', 'DD/MM/YYYY') AND
TO_DATE('07/10/2021', 'DD/MM/YYYY') then
tutar1:=(r.tutar)+tutar1;
--message(r.tutar);
elsif r.varis_tar between TO_DATE('07/10/2021', 'DD/MM/YYYY') AND
TO_DATE('14/10/2021', 'DD/MM/YYYY') then
tutar2:=(r.tutar)+tutar2;
--message(r.tutar);
elsif r.varis_tar between TO_DATE('14/10/2021', 'DD/MM/YYYY') AND
TO_DATE('21/10/2021', 'DD/MM/YYYY') then
tutar3:=(r.tutar)+tutar3;
--message(r.tutar);
elsif r.varis_tar between TO_DATE('21/10/2021', 'DD/MM/YYYY') AND
TO_DATE('31/10/2021', 'DD/MM/YYYY') then
tutar4:=(r.tutar)+tutar4;
--message(r.tutar);
end if;
end loop;
I tried to get the dates the same way for all the months. I tried that, but it worked wrong.
where trunc(varis_tar) BETWEEN TO_DATE('1', 'DD') AND
TO_DATE('31', 'DD')
if r.varis_tar between TO_DATE('1', 'DD') AND
TO_DATE('07', 'DD') then
elsif r.varis_tar between TO_DATE('7', 'DD') AND
TO_DATE('14', 'DD') then
elsif r.varis_tar between TO_DATE('14', 'DD') AND
TO_DATE('21', 'DD') then
elsif r.varis_tar between TO_DATE('21', 'DD') AND
TO_DATE('31', 'DD') then
I don't know if I'am understanding it correctly but:
try if extract(day from varis_tar) between 1 and 7
or more complex
l_week := to_char(varis_tar,'W'); --week number
if l_week = 1 then --first week
elsif l_week = 2 etc...
Your code has several issues:
date in Oracle is actually a datetime, so between will not count any time after the midnight of the upper boundary.
you count the midnight of the week's end twice: in current week and in the next week (between includes both boundaries).
you do not need any PL/SQL and especially a cursor loop, because it occupy resources during calculation outside of SQL context.
Use datetime format to calculate weeks, because it is easy to read and understand. Then group by corresponding components.
with a as (
select
date '2021-01-01' - 1 + level as dt
, level as val
from dual
connect by level < 400
)
, b as (
select
dt
, val
/*Map 29, 30 and 31 to 28*/
, to_char(
least(dt, trunc(dt, 'mm') + 27)
, 'yyyymmw'
) as w
from a
)
select
substr(w, 1, 4) as y
, substr(w, 5, 2) as m
, substr(w, -1) as w
, sum(val) as val
, min(dt) as dt_from
, max(dt) as dt_to
from b
group by
w
Y | M | W | VAL | DT_FROM | DT_TO
:--- | :- | :- | ---: | :--------- | :---------
2021 | 01 | 1 | 28 | 2021-01-01 | 2021-01-07
2021 | 01 | 2 | 77 | 2021-01-08 | 2021-01-14
2021 | 01 | 3 | 126 | 2021-01-15 | 2021-01-21
2021 | 01 | 4 | 265 | 2021-01-22 | 2021-01-31
2021 | 02 | 1 | 245 | 2021-02-01 | 2021-02-07
2021 | 02 | 2 | 294 | 2021-02-08 | 2021-02-14
2021 | 02 | 3 | 343 | 2021-02-15 | 2021-02-21
2021 | 02 | 4 | 392 | 2021-02-22 | 2021-02-28
2021 | 03 | 1 | 441 | 2021-03-01 | 2021-03-07
2021 | 03 | 2 | 490 | 2021-03-08 | 2021-03-14
2021 | 03 | 3 | 539 | 2021-03-15 | 2021-03-21
2021 | 03 | 4 | 855 | 2021-03-22 | 2021-03-31
2021 | 04 | 1 | 658 | 2021-04-01 | 2021-04-07
2021 | 04 | 2 | 707 | 2021-04-08 | 2021-04-14
2021 | 04 | 3 | 756 | 2021-04-15 | 2021-04-21
2021 | 04 | 4 | 1044 | 2021-04-22 | 2021-04-30
2021 | 05 | 1 | 868 | 2021-05-01 | 2021-05-07
2021 | 05 | 2 | 917 | 2021-05-08 | 2021-05-14
2021 | 05 | 3 | 966 | 2021-05-15 | 2021-05-21
2021 | 05 | 4 | 1465 | 2021-05-22 | 2021-05-31
2021 | 06 | 1 | 1085 | 2021-06-01 | 2021-06-07
2021 | 06 | 2 | 1134 | 2021-06-08 | 2021-06-14
2021 | 06 | 3 | 1183 | 2021-06-15 | 2021-06-21
2021 | 06 | 4 | 1593 | 2021-06-22 | 2021-06-30
2021 | 07 | 1 | 1295 | 2021-07-01 | 2021-07-07
2021 | 07 | 2 | 1344 | 2021-07-08 | 2021-07-14
2021 | 07 | 3 | 1393 | 2021-07-15 | 2021-07-21
2021 | 07 | 4 | 2075 | 2021-07-22 | 2021-07-31
2021 | 08 | 1 | 1512 | 2021-08-01 | 2021-08-07
2021 | 08 | 2 | 1561 | 2021-08-08 | 2021-08-14
2021 | 08 | 3 | 1610 | 2021-08-15 | 2021-08-21
2021 | 08 | 4 | 2385 | 2021-08-22 | 2021-08-31
2021 | 09 | 1 | 1729 | 2021-09-01 | 2021-09-07
2021 | 09 | 2 | 1778 | 2021-09-08 | 2021-09-14
2021 | 09 | 3 | 1827 | 2021-09-15 | 2021-09-21
2021 | 09 | 4 | 2421 | 2021-09-22 | 2021-09-30
2021 | 10 | 1 | 1939 | 2021-10-01 | 2021-10-07
2021 | 10 | 2 | 1988 | 2021-10-08 | 2021-10-14
2021 | 10 | 3 | 2037 | 2021-10-15 | 2021-10-21
2021 | 10 | 4 | 2995 | 2021-10-22 | 2021-10-31
2021 | 11 | 1 | 2156 | 2021-11-01 | 2021-11-07
2021 | 11 | 2 | 2205 | 2021-11-08 | 2021-11-14
2021 | 11 | 3 | 2254 | 2021-11-15 | 2021-11-21
2021 | 11 | 4 | 2970 | 2021-11-22 | 2021-11-30
2021 | 12 | 1 | 2366 | 2021-12-01 | 2021-12-07
2021 | 12 | 2 | 2415 | 2021-12-08 | 2021-12-14
2021 | 12 | 3 | 2464 | 2021-12-15 | 2021-12-21
2021 | 12 | 4 | 3605 | 2021-12-22 | 2021-12-31
2022 | 01 | 1 | 2583 | 2022-01-01 | 2022-01-07
2022 | 01 | 2 | 2632 | 2022-01-08 | 2022-01-14
2022 | 01 | 3 | 2681 | 2022-01-15 | 2022-01-21
2022 | 01 | 4 | 3915 | 2022-01-22 | 2022-01-31
2022 | 02 | 1 | 1194 | 2022-02-01 | 2022-02-03
db<>fiddle here
Or the same in columns:
with a as (
select
date '2021-01-01' - 1 + level as dt
, level as val
from dual
connect by level < 400
)
, b as (
select
val
/*Map 29, 30 and 31 to 28*/
, to_char(dt, 'yyyymm') as m
, to_char(
least(dt, trunc(dt, 'mm') + 27)
, 'w'
) as w
from a
)
select
substr(m, 1, 4) as y
, substr(m, 5, 2) as m
, tutar1
, tutar2
, tutar3
, tutar4
from b
pivot(
sum(val)
for w in (
1 as tutar1, 2 as tutar2
, 3 as tutar3, 4 as tutar4
)
)
Y | M | TUTAR1 | TUTAR2 | TUTAR3 | TUTAR4
:--- | :- | -----: | -----: | -----: | -----:
2021 | 01 | 28 | 77 | 126 | 265
2021 | 02 | 245 | 294 | 343 | 392
2021 | 03 | 441 | 490 | 539 | 855
2021 | 04 | 658 | 707 | 756 | 1044
2021 | 05 | 868 | 917 | 966 | 1465
2021 | 06 | 1085 | 1134 | 1183 | 1593
2021 | 07 | 1295 | 1344 | 1393 | 2075
2021 | 08 | 1512 | 1561 | 1610 | 2385
2021 | 09 | 1729 | 1778 | 1827 | 2421
2021 | 10 | 1939 | 1988 | 2037 | 2995
2021 | 11 | 2156 | 2205 | 2254 | 2970
2021 | 12 | 2366 | 2415 | 2464 | 3605
2022 | 01 | 2583 | 2632 | 2681 | 3915
2022 | 02 | 1194 | null | null | null
db<>fiddle here
I am using Snowflake SQL, but I guess this can be solved by any sql. So I have data like this:
RA_MEMBER_ID YEAR QUARTER MONTH Monthly_TOTAL_PURCHASE CATEGORY
1000 2020 1 1 105 CAT10
1000 2020 1 1 57 CAT13
1000 2020 1 2 107 CAT10
1000 2020 1 2 59 CAT13
1000 2020 1 3 109 CAT11
1000 2020 1 3 61 CAT14
1000 2020 2 4 111 CAT11
1000 2020 2 4 63 CAT14
1000 2020 2 5 113 CAT12
1000 2020 2 5 65 CAT15
1000 2020 2 6 115 CAT12
1000 2020 2 6 67 CAT15
And I need data like this:
RA_MEMBER_ID YEAR QUARTER MONTH Monthly_TOTAL_PURCHASE CATEGORY Monthly_rank Quarterly_Total_purchase Quarter_category Quarter_rank Yearly_Total_purchase Yearly_category Yearly_rank
1000 2020 1 1 105 CAT10 1 105 CAT10 1 105 CAT10 1
1000 2020 1 1 57 CAT13 2 57 CAT13 2 57 CAT13 2
1000 2020 1 2 107 CAT10 1 212 CAT10 1 212 CAT10 1
1000 2020 1 2 59 CAT13 2 116 CAT13 2 116 CAT13 2
1000 2020 1 3 109 CAT11 1 212 CAT10 1 212 CAT10 1
1000 2020 1 3 61 CAT14 2 116 CAT13 2 116 CAT13 2
1000 2020 2 4 111 CAT11 1 111 CAT11 1 212 CAT10 1
1000 2020 2 4 63 CAT14 2 63 CAT14 2 124 CAT14 2
1000 2020 2 5 113 CAT12 1 113 CAT12 1 212 CAT10 1
1000 2020 2 5 65 CAT15 2 65 CAT15 2 124 CAT14 2
1000 2020 2 6 115 CAT12 1 228 CAT12 1 228 CAT12 1
1000 2020 2 6 67 CAT15 2 132 CAT15 2 132 CAT15 2
So basically, I have the top two categories by purchase amount for the first 6 months. I need the same for quarterly based on which month of the quarter it is. So let's say it is February, then the top 2 categories and amounts should be calculated based on both January and February. For March we have to get the quarter data by taking all three months. From April it will be the same as monthly rank, for May again calculate based on April and May. Similarly for Yearly also.
I have tried a lot of things but nothing seems to give me what I want.
The solution should be generic enough because there can be many other months and years.
I really need help in this.
Not sure if below is what you are after. I assume that everything is category based:
create or replace table test (
ra_member_id int,
year int,
quarter int,
month int,
monthly_purchase int,
category varchar
);
insert into test values
(1000, 2020, 1,1, 105, 'cat10'),
(1000, 2020, 1,1, 57, 'cat13'),
(1000, 2020, 1,2, 107, 'cat10'),
(1000, 2020, 1,2, 59, 'cat13'),
(1000, 2020, 1,3, 109, 'cat11'),
(1000, 2020, 1,3, 61, 'cat14'),
(1000, 2020, 2,4, 111, 'cat11'),
(1000, 2020, 2,4, 63, 'cat14'),
(1000, 2020, 2,5, 113, 'cat12'),
(1000, 2020, 2,5, 65, 'cat15'),
(1000, 2020, 2,6, 115, 'cat12'),
(1000, 2020, 2,6, 67, 'cat15');
WITH BASE as (
select
RA_MEMBER_ID,
YEAR,
QUARTER,
MONTH,
CATEGORY,
MONTHLY_PURCHASE,
LAG(MONTHLY_PURCHASE) OVER (PARTITION BY QUARTER, CATEGORY ORDER BY MONTH) AS QUARTERLY_PURCHASE_LAG,
IFNULL(QUARTERLY_PURCHASE_LAG, 0) + MONTHLY_PURCHASE AS QUARTERLY_PURCHASE,
LAG(MONTHLY_PURCHASE) OVER (PARTITION BY YEAR, CATEGORY ORDER BY MONTH) AS YEARLY_PURCHASE_LAG,
IFNULL(YEARLY_PURCHASE_LAG, 0) + MONTHLY_PURCHASE AS YEARLY_PURCHASE
FROM
TEST
),
BASE_RANK AS (
SELECT
RA_MEMBER_ID,
YEAR,
QUARTER,
MONTH,
CATEGORY,
MONTHLY_PURCHASE,
RANK() OVER (PARTITION BY MONTH ORDER BY MONTHLY_PURCHASE DESC) as MONTHLY_RANK,
QUARTERLY_PURCHASE,
RANK() OVER (PARTITION BY QUARTER ORDER BY QUARTERLY_PURCHASE DESC) as QUARTERLY_RANK,
YEARLY_PURCHASE,
RANK() OVER (PARTITION BY YEAR ORDER BY YEARLY_PURCHASE DESC) as YEARLY_RANK
FROM BASE
),
MAIN AS (
SELECT
RA_MEMBER_ID,
YEAR,
QUARTER,
MONTH,
CATEGORY,
MONTHLY_PURCHASE,
MONTHLY_RANK,
QUARTERLY_PURCHASE,
QUARTERLY_RANK,
YEARLY_PURCHASE,
YEARLY_RANK
FROM BASE_RANK
)
SELECT * FROM MAIN
ORDER BY YEAR, QUARTER, MONTH
;
Result:
+--------------+------+---------+-------+----------+------------------+--------------+--------------------+----------------+-----------------+-------------+
| RA_MEMBER_ID | YEAR | QUARTER | MONTH | CATEGORY | MONTHLY_PURCHASE | MONTHLY_RANK | QUARTERLY_PURCHASE | QUARTERLY_RANK | YEARLY_PURCHASE | YEARLY_RANK |
|--------------+------+---------+-------+----------+------------------+--------------+--------------------+----------------+-----------------+-------------|
| 1000 | 2020 | 1 | 1 | cat10 | 105 | 1 | 105 | 4 | 105 | 9 |
| 1000 | 2020 | 1 | 1 | cat13 | 57 | 2 | 57 | 6 | 57 | 12 |
| 1000 | 2020 | 1 | 2 | cat10 | 107 | 1 | 212 | 1 | 212 | 3 |
| 1000 | 2020 | 1 | 2 | cat13 | 59 | 2 | 116 | 2 | 116 | 6 |
| 1000 | 2020 | 1 | 3 | cat11 | 109 | 1 | 109 | 3 | 109 | 8 |
| 1000 | 2020 | 1 | 3 | cat14 | 61 | 2 | 61 | 5 | 61 | 11 |
| 1000 | 2020 | 2 | 4 | cat11 | 111 | 1 | 111 | 4 | 220 | 2 |
| 1000 | 2020 | 2 | 4 | cat14 | 63 | 2 | 63 | 6 | 124 | 5 |
| 1000 | 2020 | 2 | 5 | cat12 | 113 | 1 | 113 | 3 | 113 | 7 |
| 1000 | 2020 | 2 | 5 | cat15 | 65 | 2 | 65 | 5 | 65 | 10 |
| 1000 | 2020 | 2 | 6 | cat12 | 115 | 1 | 228 | 1 | 228 | 1 |
| 1000 | 2020 | 2 | 6 | cat15 | 67 | 2 | 132 | 2 | 132 | 4 |
+--------------+------+---------+-------+----------+------------------+--------------+--------------------+----------------+-----------------+-------------+
Currently my Transaction Table has customer's transaction data for each month. Account_ID identifies the customer's ID. Order_ID is the number of orders that the customer had made. Reporting_week_start_date is the week which begins on Monday where each transaction is made (Date_Purchased).
How do i create a new table to identify the customer_status after each transaction has been made? Note that the new table has the Reporting_week_start_date until current date despite no transactions has been made .
Customer_Status
- New : customers who made their first paid subscription
- Recurring : customers with continuous payment
- Churned : when customers' subscriptions had expired and there's no renewal within the next month/same month
- Reactivated : customers who had churned and then returned to re-subscribe
Transaction Table
Account_ID | Order_ID | Reporting_week_start_date| Date_Purchased | Data_Expired
001 | 1001 | 31 Dec 2018 | 01 Jan 2019 | 08 Jan 2019
001 | 1001 | 07 Jan 2019 | 08 Jan 2019 | 15 Jan 2019
001 | 1001 | 14 Jan 2019 | 15 Jan 2019 | 22 Jan 2019 #Transaction 1
001 | 1001 | 21 Jan 2019 | 22 Jan 2019 | 29 Jan 2019
001 | 1001 | 28 Jan 2019 | 29 Jan 2019 | 31 Jan 2019
001 | 1002 | 28 Jan 2019 | 01 Feb 2019 | 08 Feb 2019
001 | 1002 | 04 Feb 2019 | 08 Feb 2019 | 15 Feb 2019 #Transaction 2
001 | 1002 | 11 Feb 2019 | 15 Feb 2019 | 22 Feb 2019
001 | 1002 | 18 Feb 2019 | 22 Feb 2019 | 28 Feb 2019
001 | 1003 | 25 Feb 2019 | 01 Mar 2019 | 08 Mar 2019
001 | 1003 | 04 Mar 2019 | 08 Mar 2019 | 15 Mar 2019
001 | 1003 | 11 Mar 2019 | 15 Mar 2019 | 22 Mar 2019 #Transaction 3
001 | 1003 | 18 Mar 2019 | 22 Mar 2019 | 29 Mar 2019
001 | 1003 | 25 Mar 2019 | 29 Mar 2019 | 31 Mar 2019
001 | 1004 | 27 May 2019 | 01 Jun 2019 | 08 Jun 2019
001 | 1004 | 03 Jun 2019 | 08 Jun 2019 | 15 Jun 2019 #Transaction 4
001 | 1004 | 10 Jun 2019 | 15 Jun 2019 | 22 Jun 2019
001 | 1004 | 17 Jun 2019 | 22 Jun 2019 | 29 Jun 2019
001 | 1004 | 24 Jun 2019 | 29 Jun 2019 | 30 Jun 2019
Expected Output
Account_ID | Order_ID | Reporting_week_start_date| Customer_status
001 | 1001 | 31 Dec 2018 | New
001 | 1001 | 07 Jan 2019 | New #Transaction 1
001 | 1001 | 14 Jan 2019 | New
001 | 1001 | 21 Jan 2019 | New
001 | 1001 | 28 Jan 2019 | New
001 | 1002 | 28 Jan 2019 | Recurring
001 | 1002 | 04 Feb 2019 | Recurring #Transaction 2
001 | 1002 | 11 Feb 2019 | Recurring
001 | 1002 | 18 Feb 2019 | Recurring
001 | 1003 | 25 Feb 2019 | Churned
001 | 1003 | 04 Mar 2019 | Churned #Transaction 3
001 | 1003 | 11 Mar 2019 | Churned
001 | 1003 | 18 Mar 2019 | Churned
001 | 1003 | 25 Mar 2019 | Churned
001 | - | 1 Apr 2019 | Churned
001 | - | 08 Apr 2019 | Churned
001 | - | 15 Apr 2019 | Churned
001 | - | 22 Apr 2019 | Churned
001 | - | 29 Apr 2019 | Churned
001 | - | 29 Apr 2019 | Churned
001 | - | 06 May 2019 | Churned
001 | - | 13 May 2019 | Churned
001 | - | 20 May 2019 | Churned
001 | - | 27 May 2019 | Churned
001 | 1004 | 27 May 2019 | Reactivated
001 | 1004 | 03 Jun 2019 | Reactivated #Transaction 4
001 | 1004 | 10 Jun 2019 | Reactivated
001 | 1004 | 17 Jun 2019 | Reactivated
001 | 1004 | 24 Jun 2019 | Reactivated'
...
...
...
current date
I think you just want window functions and case logic. Assuming the date you are referring to is Reporting_week_start_date, then the logic looks something like this:
select t.*,
(case when Reporting_week_start_date = min(Reporting_week_start_date) over (partition by account_id)
then 'New'
when Reporting_week_start_date < dateadd(lag(Reporting_week_start_date) over (partition by account_id order by Reporting_week_start_date), interval 1 month)
then 'Recurring'
when Reporting_week_start_date < dateadd(lead(Reporting_week_start_date) over (partition by account_id order by Reporting_week_start_date), interval -1 month)
then 'Churned'
else 'Reactivated'
end) as status
from transactions t;
These are not exactly the rules you have specified. But they seem very reasonable interpretations of what you want to do.
I expect to select from two date, automatically displaying consecutive time rows data.
e.g:
Select *
from somefunction('2013/5','2019/3');
Expected result:
Year | Month
-----+------
2013 | 5
2013 | 6
.. | ..
2013 | 12
.. | ..
.. | ..
2019 | 1
2019 | 2
2019 | 3
I have solved the problem, and the solution is provided here .
declare #dStart datetime = '2013/05/01'
,#dEnd datetime = '2019/03/31';
SELECT year(Dateadd(month,number,#dStart)) as year,month(Dateadd(month,number,#dStart)) as month
FROM master..spt_values
WHERE
type = 'P'
AND number <= DATEDIFF(month, #dStart, #dEnd)
GO
year | month
---: | ----:
2013 | 5
2013 | 6
2013 | 7
2013 | 8
2013 | 9
2013 | 10
2013 | 11
2013 | 12
2014 | 1
2014 | 2
2014 | 3
2014 | 4
2014 | 5
2014 | 6
2014 | 7
2014 | 8
2014 | 9
2014 | 10
2014 | 11
2014 | 12
2015 | 1
2015 | 2
2015 | 3
2015 | 4
2015 | 5
2015 | 6
2015 | 7
2015 | 8
2015 | 9
2015 | 10
2015 | 11
2015 | 12
2016 | 1
2016 | 2
2016 | 3
2016 | 4
2016 | 5
2016 | 6
2016 | 7
2016 | 8
2016 | 9
2016 | 10
2016 | 11
2016 | 12
2017 | 1
2017 | 2
2017 | 3
2017 | 4
2017 | 5
2017 | 6
2017 | 7
2017 | 8
2017 | 9
2017 | 10
2017 | 11
2017 | 12
2018 | 1
2018 | 2
2018 | 3
2018 | 4
2018 | 5
2018 | 6
2018 | 7
2018 | 8
2018 | 9
2018 | 10
2018 | 11
2018 | 12
2019 | 1
2019 | 2
2019 | 3
db<>fiddle here
This may be so last year but I'm using SQL Server 2005
stmpdate intime
----------------------
2014-10-08 08:04:43
2014-10-09 07:57:13
2014-10-10 07:57:14
2014-10-16 07:79:56
2014-10-17 07:45:56
I have this table. It keeps check-in time of the employee, but this employee didn't check-in everyday in the month. So what I want it to be is something like this
stmpdate intime
1 2014-10-01
2 2014-10-02
3 2014-10-03
4 2014-10-04
5 2014-10-05
6 2014-10-06
7 2014-10-07
8 2014-10-08 08:04:43
9 2014-10-09 07:57:13
10 2014-10-10 07:57:14
11 2014-10-11
12 2014-10-12
13 2014-10-13
14 2014-10-14
15 2014-10-15
16 2014-10-16 07:59:56
17 2014-10-17 07:45:56
18 2014-10-18
19 2014-10-19
20 2014-10-20
21 2014-10-21
22 2014-10-22
23 2014-10-23
24 2014-10-24
25 2014-10-25
26 2014-10-26
27 2014-10-27
28 2014-10-28
29 2014-10-29
30 2014-10-30
31 2014-10-31
I tried to make a temp table which contains every date in the month, and then left join it with the first table I mentioned, but it seemed to not work.
declare #datetemp table (
stmpdate varchar(10)
);
insert into #datetemp
SELECT '2014-10-01'
UNION ALL
SELECT '2014-10-02'
UNION ALL
SELECT '2014-10-03'
....
and
SELECT dtt.stmpdate, intime
FROM #datetemp dtt left join v_dayTimesheet
on dtt.stmpdate=v_dayTimesheet.stmpdate
WHERE (emp_no = '001234567')
here is the result of query above
stmpdate intime
2014-10-08 08:04:43
2014-10-09 07:57:13
2014-10-10 07:57:14
2014-10-16 07:59:56
2014-10-17 07:45:56
and here is the result of select * from #datetemp
2014-10-01
2014-10-02
2014-10-03
2014-10-04
2014-10-05
2014-10-06
2014-10-07
2014-10-08
2014-10-09
2014-10-10
2014-10-11
2014-10-12
2014-10-13
2014-10-14
2014-10-15
2014-10-16
2014-10-17
2014-10-18
2014-10-19
2014-10-20
2014-10-21
2014-10-22
2014-10-23
2014-10-24
2014-10-25
2014-10-26
2014-10-27
2014-10-28
2014-10-29
2014-10-30
2014-10-31
you're filtering for only where emp_no has a value. if they didn't check in, it won't return on that row because you just have date info and no employee number. so you have to allow for equal or null.
SELECT dtt.stmpdate, intime
FROM #datetemp dtt
left outer join v_dayTimesheet
on dtt.stmpdate=v_dayTimesheet.stmpdate
WHERE emp_no = '001234567' or emp_no is null
also, for your dates... check this out: http://www.sqlservercurry.com/2010/03/generate-start-and-end-date-range-using.html
DECLARE
#StartDate datetime = '2010-01-01',
#EndDate datetime = '2010-03-01'
;WITH datetemp as
(
SELECT #StartDate as stmpdate
UNION ALL
SELECT DATEADD(day, 1, stmpdate)
FROM datetemp
WHERE DATEADD(day, 1, stmpdate) <= #EndDate
)
SELECT stmpdate
FROM datetemp;
you would then select from datetemp as a normal table. beware, though, a common table expression can only be used once and immediately following the with statement.
just trust me on this one... run this query and see how your blank lines occur:
SELECT dtt.stmpdate, intime, emp_no
FROM #datetemp dtt
left outer join v_dayTimesheet
on dtt.stmpdate=v_dayTimesheet.stmpdate
WHERE emp_no = '001234567' or emp_no is null
all these lines will return with emp_no = 001234567
stmpdate intime
2014-10-08 08:04:43
2014-10-09 07:57:13
2014-10-10 07:57:14
2014-10-16 07:59:56
2014-10-17 07:45:56
and all your blank lines will have null as emp_no.
I got my answer!!
SELECT dtt.stmpdate, intime
FROM #datetemp dtt left join
(
SELECT stmpdate, intime
FROM v_dayTimesheet
WHERE (emp_no = '001234567')
) as vdayTimesheet
on sparedate.stmpdate=vdayTimesheet.stampdate
ORDER BY stmpdate
this is what I want, thanks everyone
SQL Query:
SQLFIDDLEExample
SELECT t2.dt,
isnull(t1.intime, '') intime
FROM
(
SELECT DATEADD(day,number,'2014-10-01') dt
FROM master..spt_values
WHERE Type = 'P'
AND DATEADD(day,number,'2014-10-01') >= '2014-10-01'
AND DATEADD(day,number,'2014-10-01') < '2014-11-01'
) t2
LEFT JOIN Table1 t1
ON t1.stmpdate = t2.dt
Result:
| DT | INTIME |
|--------------------------------|----------|
| October, 01 2014 00:00:00+0000 | |
| October, 02 2014 00:00:00+0000 | |
| October, 03 2014 00:00:00+0000 | |
| October, 04 2014 00:00:00+0000 | |
| October, 05 2014 00:00:00+0000 | |
| October, 06 2014 00:00:00+0000 | |
| October, 07 2014 00:00:00+0000 | |
| October, 08 2014 00:00:00+0000 | 08:04:43 |
| October, 09 2014 00:00:00+0000 | 07:57:13 |
| October, 10 2014 00:00:00+0000 | 07:57:14 |
| October, 11 2014 00:00:00+0000 | |
| October, 12 2014 00:00:00+0000 | |
| October, 13 2014 00:00:00+0000 | |
| October, 14 2014 00:00:00+0000 | |
| October, 15 2014 00:00:00+0000 | |
| October, 16 2014 00:00:00+0000 | 07:79:56 |
| October, 17 2014 00:00:00+0000 | 07:45:56 |
| October, 18 2014 00:00:00+0000 | |
| October, 19 2014 00:00:00+0000 | |
| October, 20 2014 00:00:00+0000 | |
| October, 21 2014 00:00:00+0000 | |
| October, 22 2014 00:00:00+0000 | |
| October, 23 2014 00:00:00+0000 | |
| October, 24 2014 00:00:00+0000 | |
| October, 25 2014 00:00:00+0000 | |
| October, 26 2014 00:00:00+0000 | |
| October, 27 2014 00:00:00+0000 | |
| October, 28 2014 00:00:00+0000 | |
| October, 29 2014 00:00:00+0000 | |
| October, 30 2014 00:00:00+0000 | |
| October, 31 2014 00:00:00+0000 | |