SQL Server, running total, reset for each month and sum again - sql-server

I have a calendar table where working days are marked.
Now I need a running total called "current_working_day" which sums up the working days until the end of a month and restarts again.
This is my query:
select
WDAYS.Date,
WDAYS.DayName,
WDAYS.WorkingDay,
sum(WDAYS.WorkingDay) OVER(order by (Date), MONTH(Date), YEAR(Date)) as 'current_working_day',
sum(WDAYS.WorkingDay) OVER(PARTITION by YEAR(WDAYS.Date), MONTH(WDAYS.Date) ) total_working_days_per_month
from WDAYS
where YEAR(WDAYS.Date) = 2022
This is my current output
Date
DayName
WorkingDay
current_working_day
total_working_days_per_month
2022-01-27
Thursday
1
19
21
2022-01-28
Friday
1
20
21
2022-01-29
Saturday
0
20
21
2022-01-30
Sunday
0
20
21
2022-01-31
Monday
1
21
21
2022-02-01
Tuesday
1
22
20
2022-02-02
Wednesday
1
23
20
2022-02-03
Thursday
1
24
20
But the column "current_workind_day" should be like this
Date
DayName
WorkingDay
current_working_day
total_working_days_per_month
2022-01-27
Thursday
1
19
21
2022-01-28
Friday
1
20
21
2022-01-29
Saturday
0
20
21
2022-01-30
Sunday
0
20
21
2022-01-31
Monday
1
21
21
2022-02-01
Tuesday
1
1
20
2022-02-02
Wednesday
1
2
20
2022-02-03
Thursday
1
3
20
Thanks for any advice.

You can try to use PARTITION by with EOMONTH function which might get the same result but better performance, then you might only need to order by Date instead of using the function with the date.
select
WDAYS.Date,
WDAYS.DayName,
WDAYS.WorkingDay,
sum(WDAYS.WorkingDay) OVER(PARTITION by EOMONTH(WDAYS.Date) order by Date) as 'current_working_day',
sum(WDAYS.WorkingDay) OVER(PARTITION by EOMONTH(WDAYS.Date) ) total_working_days_per_month
from WDAYS
where YEAR(WDAYS.Date) = 2022

Related

SQL Server PIVOT creating all Null Values

I have the following data I am trying to pivot. My goal is one row for each Label, and each week becomes a column with the rate as the week's value.
Label
Week
Rate
51220
Week 0
-11
51220
Week 1
-41
51220
Week 2
159
51220
Week 3
117
51220
Week 4
207
51220
Week 5
-37
51220
Week 6
138
51220
Week 7
139
51220
Week 8
-42
51220
Week 9
-45
51220
Week 10
-82
51220
Week 11
-85
51220
Week 12
-25
51347
Week 0
23
51347
Week 1
24
51347
Week 2
25
51347
Week 3
25
51347
Week 4
25
51347
Week 5
24
51347
Week 6
24
51347
Week 7
24
51347
Week 8
24
51347
Week 9
24
51347
Week 10
24
51347
Week 11
24
51347
Week 12
23
Here my my query:
SELECT * FROM table1
PIVOT (
SUM(Rate) FOR Week IN (Week0,Week1,Week2,Week3,Week4,Week5,Week6,Week7,Week8,Week9,Week10,Week11,Week12)
) pivot_table;
This results are always NULL. What am I doing incorrectly? I'm following several tutorials with no success.
Yeah, those brackets will do it.
SELECT *
FROM (VALUES('51220','Week 0',-11)
,('51220','Week 1',-41)
,('51347','Week 1', 24)
) table1(Label, Week, Rate)
PIVOT (SUM(rate) FOR WEEK IN ([Week 0],[Week 1])) AS pivot_table

Oracle - Cycle detected while executing recursive 'WITH' query

I'm doing a basic example of recursive query with oracle sql. I'm computing future months of the format MON-YY. I managed to have a seemingly correct query but I don't understand the break condition with a WITH query.
I'm trying to break on the year value (for example stop when you reach 2020), but it detects a cycle while doing that. If I break on the month value (e.g. December), it works.
Here's my query with a month based break:
with
prochains_mois(mois, annee) as (
select 'sep' as mois, 19 as annee
from dual
union all
select
case mois
when 'jan' then 'fev'
when 'fev' then 'mar'
when 'mar' then 'avr'
when 'avr' then 'mai'
when 'mai' then 'jun'
when 'jun' then 'jui'
when 'jui' then 'aou'
when 'aou' then 'sep'
when 'sep' then 'oct'
when 'oct' then 'nov'
when 'nov' then 'dec'
when 'dec' then 'jan'
end,
case mois
when 'dec' then annee + 1
else annee
end
from prochains_mois r
where mois <> 'dec'
)
select * from prochains_mois;
If I do this, it returns a consistent result.
MOI ANNEE
--- ----------
sep 19
oct 19
nov 19
dec 19
Now if I try to break the recursive query on the year, let's say 2020, so I change the where condition in the with clause to :
where annee < 20
Then I get :
ORA-32044: cycle detected while executing recursive WITH query
I tried to break with a later month to see if my year addition works correctly, it seems to be the case. If I break on march, I get the January and February correctly :
where mois <> 'mar'
gives
MOI ANNEE
--- ----------
sep 19
oct 19
nov 19
dec 19
jan 20
fev 20
mar 20
Use DATEs:
with prochains_mois( value ) as (
select DATE '2019-09-01' from dual
union all
select ADD_MONTHS( value, 1 )
FROM prochains_mois
WHERE value < DATE '2020-12-01'
)
select SUBSTR( TO_CHAR( value, 'mon', 'NLS_DATE_LANGUAGE=FRENCH' ), 1, 3 ) AS mois,
TO_CHAR( value, 'RR' ) AS annee
from prochains_mois;
Output:
MOIS | ANNEE
:--- | :----
sep | 19
oct | 19
nov | 19
dec | 19
jan | 20
fev | 20
mar | 20
avr | 20
mai | 20
jui | 20
jui | 20
aou | 20
sep | 20
oct | 20
nov | 20
dec | 20
or use your query and check that the month and year do not match:
with
prochains_mois(mois, annee) as (
select 'sep' as mois, 19 as annee
from dual
union all
select
case mois
when 'jan' then 'fev'
when 'fev' then 'mar'
when 'mar' then 'avr'
when 'avr' then 'mai'
when 'mai' then 'jun'
when 'jun' then 'jui'
when 'jui' then 'aou'
when 'aou' then 'sep'
when 'sep' then 'oct'
when 'oct' then 'nov'
when 'nov' then 'dec'
when 'dec' then 'jan'
end,
case mois
when 'dec' then annee + 1
else annee
end
from prochains_mois r
where ( mois, annee ) NOT IN ( ( 'dec', 20 ) )
)
select * from prochains_mois;
Output:
MOIS | ANNEE
:--- | ----:
sep | 19
oct | 19
nov | 19
dec | 19
jan | 20
fev | 20
mar | 20
avr | 20
mai | 20
jun | 20
jui | 20
aou | 20
sep | 20
oct | 20
nov | 20
dec | 20
db<>fiddle here
Your main issue is that you're trying to manipulate dates using strings/numbers. Don't do that; if you're working with dates, use dates!
E.g. you can do what you're after like so:
WITH prochains_mois (mnth_dt) AS (SELECT TRUNC(sysdate, 'mm') mnth_dt
FROM dual
UNION ALL
SELECT add_months(mnth_dt, 1) mnth_dt
FROM prochains_mois
WHERE add_months(mnth_dt, 1) < add_months(TRUNC(sysdate, 'yyyy'), 12))
SELECT mnth_dt,
to_char(mnth_dt, 'mon') mois,
to_char(mnth_dt, 'yy') annee
FROM prochains_mois;
MNTH_DT MOIS ANNEE
----------- ---- -----
01/09/2019 sep 19
01/10/2019 oct 19
01/11/2019 nov 19
01/12/2019 dec 19
N.B. You could simplify the predicate in the recursive sub-factored query to mnth_dt < add_months(TRUNC(SYSDATE, 'yyyy'), 11).
This works by taking the start date (here, I've used sysdate) and finding the first of the month (by using the optional second parameter of TRUNC to specify the level we're truncating it to).
Then we simply add a month to each date until we hit the last month of the start date's year.
Only after you've got the dates do you then output the data in the format you require using to_char.

SSRS - Using specific Row Number

I have a SQL query where I am getting the row number for a count of employees per division and per month at the beginning of the month and the end of the month. To do that, I use a payroll end date which is a weekly date. So in essence I have 4 dates where employee counts are shown. Some months have 5 dates which makes the row count for that month 5 instead of 4.
I then need to build an SSRS report to show only the first employee count and the last employee count per division, per month. I have the first number since I am using =IIF(Fields!RowNumber.Value = 1, Fields!EMPCOUNT.Value, 0)
The problem I have now is getting the last employee count where I need to conditionally select a count where row number needs to be 5 if exists or 4 if it doesn't exist. I'm not sure how to get the expression to work in SSRS. Sample data is below.
PRCo EMPCOUNT udDivision PREndDate ROWNUM Type
1 89 Civil 2018-01-06 00:00:00 1 1
1 97 Civil 2018-01-13 00:00:00 2 1
1 97 Civil 2018-01-20 00:00:00 3 1
1 97 Civil 2018-01-27 00:00:00 4 1
1 16 Colorado 2018-01-06 00:00:00 1 1
1 18 Colorado 2018-01-13 00:00:00 2 1
1 14 Colorado 2018-01-20 00:00:00 3 1
1 10 Colorado 2018-01-27 00:00:00 4 1
1 94 Civil 2018-02-03 00:00:00 1 2
1 91 Civil 2018-02-10 00:00:00 2 2
1 92 Civil 2018-02-17 00:00:00 3 2
1 91 Civil 2018-02-24 00:00:00 4 2
1 16 Colorado 2018-02-03 00:00:00 1 2
1 16 Colorado 2018-02-10 00:00:00 2 2
1 18 Colorado 2018-02-17 00:00:00 3 2
1 19 Colorado 2018-02-24 00:00:00 4 2
1 92 Civil 2018-03-03 00:00:00 1 3
1 91 Civil 2018-03-10 00:00:00 2 3
1 88 Civil 2018-03-17 00:00:00 3 3
1 92 Civil 2018-03-24 00:00:00 4 3
1 90 Civil 2018-03-31 00:00:00 5 3
1 19 Colorado 2018-03-03 00:00:00 1 3
1 26 Colorado 2018-03-10 00:00:00 2 3
1 25 Colorado 2018-03-17 00:00:00 3 3
1 27 Colorado 2018-03-24 00:00:00 4 3
1 24 Colorado 2018-03-31 00:00:00 5 3
I would do this in your query rather than trying to get it to work directly in SSRS. There might be a simpler way than this but this is just based on your existing query.
Please note this is untested and just off the top of my head so it may need some editing before it will work.
SELECT * INTO #t FROM YOUR_EXISTING_QUERY
SELECT DISTINCT
PRCo
, udDivision
, YEAR(PREndDate) AS Yr
, MONTH(PREndDate) AS Mnth
, FIRST_VALUE(EMPCOUNT) OVER(PARTITION BY PRCo, udDivision, YEAR(PREndDate), MONTH(PREndDate) ORDER BY ROWNUM) AS OpeningEMPCOUNT
, LAST_VALUE(EMPCOUNT) OVER(PARTITION BY PRCo, udDivision, YEAR(PREndDate), MONTH(PREndDate) ORDER BY ROWNUM) AS CLosing_EMPCOUNT
FROM #t
Yo might need to include Type not sure what this does but you get the idea hopefully.
The FIRST_VALUE and LAST_VALUE functions simply get the first/last value within the partition defined, in your case PRCo, udDivision and then just the year and month portion of the payroll end date, the first and last positions are determined by the order clause, in this case row number.

Conditional calculation in SQL Server

friends:
I'm now have a problem about conditional calculation in SQL Server.
I have set some data from SQL Server as an example in excel like this:
No Employee Month Commission1 Commission2
1 A Jan 10 5
2 A Jan 10 4
3 B Jan 15 3
4 B Jan 15 4
5 C Jan 10 3
6 C Jan 10 4
7 D Jan 13 3
8 D Jan 13 4
9 DM Jan 0 6
10 DM Jan 0 8
11 A Feb 15 4
12 A Feb 15 5
13 B Feb 20 5
14 B Feb 20 4
15 C Feb 9 3
16 C Feb 9 4
17 D Feb 14 5
18 D Feb 14 6
19 DM Feb 0 13
20 DM Feb 0 10
And the result I want is like this:
Employee Jan No# Feb No#
A 20 2 30 2
B 30 2 40 2
C 20 2 18 2
D 26 2 28 2
DM 44 10 59 10
For every sales,Employee A,B,C,D only have commission1 as payment,the commission2 is for DM. So , in Jan , DM's commission is SUM(E2:E9)
I can do it easy in excel , but how can I do this in sql server?
I make my try code like this:
select [Month],Employee,SUM(Commission1) Commission,count(distinct([No])) No#
from table1
WHERE Employee IN ('A','B','C','D')
group by [Month],Employee
union
select 'DM' as Employee,[Month],SUM(Commission2) Commission,count(distinct([No])) No#
from table1
WHERE Employee IN ('A','B','C','D','DM')
group by [Month],Employee
And I get the result
Employee Month Commission No#
A Jan 20 2
B Jan 30 2
C Jan 20 2
D Jan 26 2
DM Jan 44 10
A Feb 30 2
B Feb 40 2
C Feb 18 2
D Feb 28 2
DM Feb 59 10
The result format is not what I want.I tried pivot after this query,but failed,it seems I only can pivot one state?
Another question: If I want the month growth automatic (In actual data , there's not only Jan and Feb) in the result ,not write [Jan],[Feb],[Mar]... in pivot code, how to do it?
Who can help me?
Thanks!
Here is a PIVOT solution:
Test data:
DECLARE #t table(Employee varchar(2), Month char(3), Commission1 int, Commission2 int)
INSERT #t values
('A','Jan',10,5 ),('A','Jan',10,4),('B','Jan',15,3),
('B','Jan',15,4 ),('C','Jan',10,3),('C','Jan',10,4),
('D','Jan',13,3 ),('D','Jan',13,4),('DM','Jan',0,6),
('DM','Jan',0,8 ),('A','Feb',15,4),('A','Feb',15,5),
('B','Feb',20,5 ),('B','Feb',20,4),('C','Feb',9,3),
('C','Feb',9,4 ),('D','Feb',14,5),('D','Feb',14,6),
('DM','Feb',0,13),('DM','Feb',0,10)
Query:
;WITH CTE as
(
SELECT
Employee, Month,
CASE WHEN Employee = 'DM' THEN
SUM(Commission2) over (partition by [Month])
ELSE Commission1 END com,
CASE WHEN Employee = 'DM'
THEN row_number() over
(PARTITION BY Employee, [Month] ORDER BY (SELECT 1)) ELSE 1 END rn
FROM #t
)
SELECT Employee, [Jan], [Feb], [Mar] -- add more months
FROM
CTE
PIVOT
(SUM(com)
FOR [Month] IN ([Jan], [Feb], [Mar])) AS pvt -- add more months
WHERE rn = 1
Result:
Employee Jan Feb Mar
A 20 30 NULL
B 30 40 NULL
C 20 18 NULL
D 26 28 NULL
DM 44 59 NULL
In SqlServer you can do so using PIVOT operator as like below:
Please refer PIVOT syntax
select tmp.employee,pv.[jan] as Jan_Commission, pv.[feb] as Feb_Commission from
(
select employee,month,commission1 from table_name
)tmp
pivot (
sum(commission1)
for [month] in ([jan],[feb])
)pv;

How to merge data to form a panel?

I have two data frames. Data frame "weather" looks like this:
weather<-data.frame(Date=c("2012-04-01","2012-04-02","2012-04-03","2012-04-04"),Day=c("Sunday","Monday","Tuesday","Wednesday"), Temp=c(86,89,81,80))
Date Day Temperature
2012-04-01 Sunday 86
2012-04-02 Monday 89
2012-04-03 Tuesday 81
2012-04-04 Wednesday 80
And, data frame "Regularity", looks like this:
Regularity<-data.frame(Date=c("2012-04-02","2012-04-04","2012-04-03","2012-04-04"),EmployeeID=c(1,1,2,2),Attendance=c(1,1,1,1))
Date EmployeeID Attendance
2012-04-02 1 1
2012-04-04 1 1
2012-04-03 2 1
2012-04-04 2 1
I want to create a panel dataframe in R of the form:
Date Day Temperature EmployeeID Attendence
2012-04-01 Sunday 86 1 0
2012-04-02 Monday 89 1 1
2012-04-03 Tuesday 81 1 0
2012-04-04 Wednesday 80 1 1
2012-04-01 Sunday 86 2 0
2012-04-02 Monday 89 2 0
2012-04-03 Tuesday 81 2 1
2012-04-04 Wednesday 80 2 1
I have tried the merge and reshape2, but in vain. I will be very grateful for any help. Thank you.
Here is how. Suppose tb1 is the first table and tb2 is the second. Then the desired result will be achieved by following:
tb2_tf<-dcast(tb2,Date~EmployeeID,value.var="Attendance")
tb<-melt(merge(tb1,tb2_tf,all=TRUE),id=1:3,variable.name="EmployeeID",value.name="Attendance")
tb$Attendance[is.na(tb$Attendance)] <- 0
tb
Date Day Temperature EmployeeID Attendance
1 2012-04-01 Sunday 86 1 0
2 2012-04-02 Monday 89 1 1
3 2012-04-03 Tuesday 81 1 0
4 2012-04-04 Wednesday 80 1 1
5 2012-04-01 Sunday 86 2 0
6 2012-04-02 Monday 89 2 0
7 2012-04-03 Tuesday 81 2 1
8 2012-04-04 Wednesday 80 2 1
I would like to see the solution without the reshape part. I suspect there is one using some form of theta join.

Resources