Ignore Sunday while generating student attendance report in SQL - sql

This code gives me the attendance report between two dates passed as a parameter.
I will pass dates respective of the month selected from the C# code.
But I want to skip Sundays while generating the attendance report. How can I achieve this?
DECLARE #startdate date = '20180109';
DECLARE #enddate date = '20180112';
DECLARE #cols as varchar(2000);
DECLARE #query as varchar(MAX);
WITH cte (startdate)
AS
(SELECT
#startdate AS startdate
UNION ALL
SELECT
DATEADD(DAY, 1, startdate) AS startdate
FROM cte
WHERE startdate < #enddate
)
select c.startdate
into #tempDates
from cte c
SELECT
#cols = STUFF((SELECT DISTINCT
',' + QUOTENAME(CONVERT(CHAR(10),
startdate, 120))
FROM #tempDates
FOR XML PATH (''), TYPE)
.value('.', 'NVARCHAR(MAX)')
, 1, 1, '')
SET #query = 'SELECT RollNo,FirstName,LastName, ' + #cols + ' from
(
select S.RollNo,U.FirstName,U.LastName,
D.startdate,
convert(CHAR(10), startdate, 120) PivotDate
from #tempDates D,Attendance A, Student S, UserDetails U
where D.startdate = A.Date and A.EnrollmentNo=S.EnrollmentNo and A.EnrollmentNo=U.userID
) x
pivot
(
count(startdate)
for PivotDate in (' + #cols + ')
) p '
EXECUTE (#query)
drop table #tempDates

How about changing #TempDates?
select c.startdate
into #tempDates
from cte c
where datename(weekday, c.startdate) <> 'Sunday';
This assumes that your internationalization settings are set to "English".

Related

Student Attendance Report Month-wise SQL Query

There are 3 tables -
Attendance (EnrollmentNo,SubjectCode,Date,Attendance)
Student (EnrollmentNo, RollNo),
UserDetails(EnrollmentNo,FirstName,LastName).
Now what I want is to display the attendance month-wise taking Roll No, Name, dates as column and Student.RollNo, UserDetails.FirstName, UserDetails.LastName, Attendance.Attendance as the data for the columns respectively.
But the problem I am facing is how to generate date columns dynamically and put the attendance data in the respective date column.
Input - Startdate and Enddate
Expected Output -
-------------------------------------------------------
| Roll No | Name | 01-09-2018 | 01-12-2018|
-------------------------------------------------------
| 15 | Suyash Gupta | 1 | 0 |
-------------------------------------------------------
| 24 | Himanshu Shukla | 2 | 2 |
-------------------------------------------------------
| 32 | Dhruv Raj Sirohi | 1 | 1 |
-------------------------------------------------------
This is my approach -
DECLARE #startdate date
DECLARE #enddate date
SET #startdate = convert(date,'01-09-2018')
SET #enddate = convert(date,'01-12-2018')
;with cte (#startdate, #enddate) as /*I don't know how to pass my date range
in cte() as this takes table column*/
(
select 1
union all
select dateadd(dd, 1, startdate)
from cte
where startdate <= enddate
)
select c.startdate
into #tempDates
from cte c
select #cols = STUFF((SELECT distinct ',' + QUOTENAME(convert(CHAR(10),
startdate, 120))
from #tempDates
FOR XML PATH(''), TYPE
).value('.', 'NVARCHAR(MAX)')
,1,1,'')
set #query = 'SELECT RollNo,FirstName,LastName, ' + #cols + ' from
(
select S.RollNo,U.FirstName,U.LastName,
D.startdate,
convert(CHAR(10), startdate, 120) PivotDate
from #tempDates D
left join Attendance A
on D.startdate = A.Date
) x
pivot
(
count(startdate)
for PivotDate in (' + #cols + ')
) p '
execute(#query)
you have some issues with your code, look at the differences in my code:
DECLARE #startdate date = '20180109';
DECLARE #enddate date = '20180112';
DECLARE #cols as varchar(2000);
DECLARE #query as varchar(MAX);
WITH cte (startdate)
AS
(SELECT
#startdate AS startdate
UNION ALL
SELECT
DATEADD(DAY, 1, startdate) AS startdate
FROM cte
WHERE startdate < #enddate)
SELECT
#cols = STUFF((SELECT DISTINCT
',' + QUOTENAME(CONVERT(CHAR(10),
startdate, 120))
FROM cte
FOR XML PATH (''), TYPE)
.value('.', 'NVARCHAR(MAX)')
, 1, 1, '')
SET #query = 'SELECT RollNo,FirstName,LastName, ' + #cols + ' from
(
select S.RollNo,U.FirstName,U.LastName,
D.startdate,
convert(CHAR(10), startdate, 120) PivotDate
from #tempDates D
left join Attendance A
on D.startdate = A.Date
) x
pivot
(
count(startdate)
for PivotDate in (' + #cols + ')
) p '
EXECUTE (#query)
Do you mean something like this:
DECLARE #StartDate AS DATETIME, #EndDate AS DATETIME
SET #StartDate='2018-01-01'
SET #EndDate='2018-01-10'
SELECT Student.RollNo, Student.FirstName, Student.LastName, Attendance.Date
FROM Attendance,Student,UserDetails
WHERE Attendance.EnrollmentNo=Student.EnrollmentNo
AND UserDetails.EnrollmentNo=Student.EnrollmentNo
AND Attendance.[Date] between #StartDate and #EndDate
UPDATE
Based on what you said in the question maybe the following code is what you need:
SELECT Student.RollNo, Student.FirstName, Student.LastName,
STUFF((SELECT ','+CAST([DATE] AS VARCHAR(30))
FROM Attendance
WHERE Attendance.EnrollmentNo=Student.EnrollmentNo
AND Attendance.[Date] between #StartDate AND #EndDate
FOR XML PATH('')
), 1, 1, '') Dates
FROM Student,UserDetails
WHERE UserDetails.EnrollmentNo=Student.EnrollmentNo
This is running code and giving me the desired output. I want to thank Lobo, who corrected me, and everyone else who had put in the efforts to help me. Thank you all and stackoverflow who provided me the platform to query the problem I was facing.
DECLARE #startdate date = '20180109';
DECLARE #enddate date = '20180112';
DECLARE #cols as varchar(2000);
DECLARE #query as varchar(MAX);
WITH cte (startdate)
AS
(SELECT
#startdate AS startdate
UNION ALL
SELECT
DATEADD(DAY, 1, startdate) AS startdate
FROM cte
WHERE startdate < #enddate
)
select c.startdate
into #tempDates
from cte c
SELECT
#cols = STUFF((SELECT DISTINCT
',' + QUOTENAME(CONVERT(CHAR(10),
startdate, 120))
FROM #tempDates
FOR XML PATH (''), TYPE)
.value('.', 'NVARCHAR(MAX)')
, 1, 1, '')
SET #query = 'SELECT RollNo,FirstName,LastName, ' + #cols + ' from
(
select S.RollNo,U.FirstName,U.LastName,
D.startdate,
convert(CHAR(10), startdate, 120) PivotDate
from #tempDates D,Attendance A, Student S, UserDetails U
where D.startdate = A.Date and A.EnrollmentNo=S.EnrollmentNo and A.EnrollmentNo=U.userID
) x
pivot
(
count(startdate)
for PivotDate in (' + #cols + ')
) p '
EXECUTE (#query)
drop table #tempDates

how to use MAX for multiple values in dyamnmic Pivot

I have a query when I'm using static Dynamic pivot it is working fine
Static Script :
Select Name, tableName,MAX([2017-07-10])[2017-07-10],MAX([2017-07-09])[2017-07-09]
from (
SELECT Target_Db_Name,
Target_Tbl_Name,
Cnt
FROM Table1 l
WHERE Name='Employee' AND
dt >= CAST(dateadd(day, -1, getdate()) as date))T
PIVOT (MAX(cnt)FOR dt IN ([2017-07-10],[2017-07-09]) )PVT
GROUP BY Name, tableName
when I'm trying to implement dynamic query in the same query I'm confused to get max values for multiple comma separated data values
Dynamic Script :
DECLARE #cols AS NVARCHAR(MAX)='';
DECLARE #query AS NVARCHAR(MAX)='';
SELECT #cols = #cols + QUOTENAME(dt) + ',' FROM (select distinct CONVERT(DATE,t)Start_dt from Events
WHERE Start_dt >= CAST(dateadd(day, -1, getdate()) as date) ) as tmp ORDER BY Start_dt desc
select #cols = substring(#cols, 0, len(#cols))
Select #query = '
Select Name, tableName,'+#cols+'
from (
SELECT Name,
tableName,
Cnt
FROM Table1 l
WHERE Name=''Employee'' AND
Start_dt >= CAST(dateadd(day, -1, getdate()) as date))T
PIVOT (MAX(Cnt)FOR Start_dt IN ('+#cols+') )PVT
GROUP BY Name, tableName
'
EXEC (#query)
So here date values are coming like this
([2017-07-10]),([2017-07-09]) in dynamic how to apply
MAX([2017-07-10]),MAX([2017-07-09])
how to get max for each date in Dynamic Pivot
Here is one way to get the Max aggregate in column list
SET #cols = stuff((SELECT DISTINCT ','+Quotename(CONVERT(DATE, Start_dt))
FROM Events
WHERE Start_dt >= Cast(Dateadd(day, -1, Getdate()) AS DATE)
ORDER BY Start_dt DESC
FOR xml path('')) ,1,1,'')
--Print #cols
SET #select_cols = stuff((SELECT DISTINCT ',Max('+Quotename(CONVERT(DATE, Start_dt))+') as '+Quotename(CONVERT(DATE, t))
FROM Events
WHERE Start_dt >= Cast(Dateadd(day, -1, Getdate()) AS DATE)
ORDER BY Start_dt DESC
FOR xml path('')) ,1,1,'')
--Print #select_cols
Select #query = '
Select Name, tableName,'+#select_cols+'
from (
SELECT Name,
tableName,
Cnt
FROM Table1 l
WHERE Name=''Employee'' AND
Start_dt >= CAST(dateadd(day, -1, getdate()) as date))T
PIVOT (MAX(Cnt)FOR Start_dt IN ('+#cols+') )PVT
GROUP BY Name, tableName
'
EXEC (#query)
Note : Your current method to convert rows into csv's isn't guaranteed to work all the time. I have used for xml path() method to do the same

Find Count With Pivot Data SQL Server

I have been displaying Day Wise Attendance Data with Pivot SQL.
declare #startdate datetime = '2016-09-26'
declare #enddate datetime = '2016-10-01'
declare #CompanyID int = 1
DECLARE #COLUMN VARCHAR(MAX), #SQL NVARCHAR(MAX);
SET #COLUMN = N'';
DECLARE #DATERANGE TABLE (DateToCheck DATE)
;WITH Temp
AS
(
SELECT DT =DATEADD(DD,0, #startdate)
WHERE DATEADD(DD, 1, #startdate) <= #enddate
UNION ALL
SELECT DATEADD(DD, 1, DT)
FROM Temp
WHERE DATEADD(DD, 1, DT) <= #enddate
)
INSERT INTO #DATERANGE
SELECT DT From Temp
SELECT #COLUMN += N', T.' + QUOTENAME(DateRanges) FROM (SELECT CAST(CONVERT(DATE, T.DateToCheck) AS VARCHAR(10)) AS DateRanges FROM #DATERANGE T group by T.DateToCheck) AS A;
SET #SQL = '
DECLARE #DATERANGE TABLE (DateToCheck DATE)
;WITH Temp
AS
(
SELECT DT =DATEADD(DD,0, #startdate)
WHERE DATEADD(DD, 1, #startdate) <= #enddate
UNION ALL
SELECT DATEADD(DD, 1, DT)
FROM Temp
WHERE DATEADD(DD, 1, DT) <= #enddate
)
INSERT INTO #DATERANGE
SELECT DT From Temp
SELECT *
FROM (
SELECT E.FirstName, E.LastName, E.Email, T.DateToCheck, COALESCE(A.val, L.val, H.val, ''Absent'') val
FROM AspNetUsers E
CROSS APPLY (
SELECT DateToCheck FROM #DATERANGE
) T--(DateToCheck)
LEFT JOIN (SELECT ''Holiday'' val, HolidayDate, CompanyID FROM Holidays) H ON H.HolidayDate = T.DateToCheck AND H.CompanyID = #CompanyID
LEFT JOIN (SELECT ''In : '' + CONVERT(VARCHAR, MIN(AttendanceDateTime), 108) + '' / Out : '' + CONVERT(VARCHAR, MAX(AttendanceDateTime), 108) val, CAST(AttendanceDateTime As DATE) As AttendanceDate, UserID FROM Attendances GROUP BY CAST(AttendanceDateTime As DATE), UserID) A ON A.AttendanceDate = T.DateToCheck AND A.UserID = E.Id
LEFT JOIN (SELECT ''Leave'' val, LeaveDate, UserID FROM LeaveApplications) L ON L.LeaveDate = T.DateToCheck AND L.UserID = E.Id
WHERE E.CompanyID = #CompanyID
) T
PIVOT (MAX(val) FOR DateToCheck IN (' + STUFF(REPLACE(#COLUMN, ', T.[', ',['), 1, 1, '') + ')) P';
EXEC sp_executesql #SQL, N'#startdate DATE, #enddate DATE, #CompanyID INT', #startdate, #enddate, #CompanyID
And below is the result set of how it's now
Now I wish to add more field to the above SQL to display counts like PresentCount, AbsentCount, HolidayCount and LeaveCount
I have already written a SQL where I could easily display these counts but, I'm unable to make it work with the above PIVOT SQL.
So in this case, the result for first row would be PresentCount = 0, AbsentCount = 6, HolidayCount = 0 and LeaveCount = 0. For Row 2 it would be PresentCount = 4, AbsentCount = 2, LeaveCount and HolidayCount both is 0.

How to create Temp Table with month columns based on date parameters?

I have a stored procedure that accepts two Dates. In my stored procedure, I need to create a temp table with the months in between the two dates as columns.
For example,
If the user passes in
1/1/2016 , 8/1/2016
I need a temp table with the columns:
January February March April May June July August
How could I create this type of temp table with columns created in this manner? With the columns being based on the two dates passed in?
The following script should get you started (and almost there):
declare #start_date DATE = '20160101'
declare #end_date DATE = '20160801'
;WITH CTE AS
(
SELECT #start_date AS cte_start_date, DATENAME(month, #start_date) AS Name,
CAST(' ALTER TABLE #myTemp ADD ' + DATENAME(month, #start_date) + ' INT ' + CHAR(13) + CHAR(10) AS VARCHAR(8000)) AS SqlStr
UNION ALL
SELECT DATEADD(MONTH, 1, cte_start_date), DATENAME(month, DATEADD(MONTH, 1, cte_start_date)) AS Name,
CAST(SqlStr + ' ALTER TABLE #myTemp ADD ' + DATENAME(month, DATEADD(MONTH, 1, cte_start_date)) + ' INT ' + CHAR(13) + CHAR(10) AS VARCHAR(8000))
FROM CTE
WHERE DATEADD(MONTH, 1, cte_start_date) <= #end_date
)
SELECT cte_start_date, Name, SqlStr
FROM CTE
Using a recursive-CTE it generates a loop between start and end date, and for each month it computes its string representation and also creates a alter script to add the columns to a temporary table.
The CTE computes the SQL script gradually, so that the final script is on the last line.
Try This ....
declare #start_date DATE = '20160101'
declare #end_date DATE = '20160801'
;WITH CTE AS
(
SELECT #start_date AS cte_start_date, DATENAME(month, #start_date) AS NAME , 0 AS Coun
UNION ALL
SELECT DATEADD(MONTH, 1, cte_start_date), DATENAME(month, DATEADD(MONTH, 1, cte_start_date)) AS NAME , 0 AS Coun
FROM CTE
WHERE DATEADD(MONTH, 1, cte_start_date) <= #end_date
)
SELECT Coun,Name
INTO #tmp1
FROM CTE
DECLARE #cols AS NVARCHAR(MAX),
#query AS NVARCHAR(MAX)
select #cols = STUFF((SELECT ',' + Name
from #tmp1
FOR XML PATH(''), TYPE
).value('.', 'NVARCHAR(MAX)')
,1,1,'')
set #query = 'SELECT ' + #cols + ' from
(
select Coun,Name
from #tmp1
) x
pivot
(
MAX(Coun)
for Name in (' + #cols + ')
) p '
execute(#query);
DROP TABLE #tmp1
It Will Return OutPut Like your expected output .......

Getting null value in the Grand Total column in the Pivot Table in sql

I have the query which returning me the number of categories in one cloumn and other column are dynamic column they are giving me the the months between start date & end date and this column are returning me the amount of the categories sold on that month.
I want to add the Grand Total at the end of the row in the query
Here's My Query
DECLARE #cols AS NVARCHAR(MAX),
#query AS NVARCHAR(MAX),
#subtotal AS FLOAT,
#startdate as datetime,
#enddate as datetime
DECLARE #ColumnsRollup AS VARCHAR (MAX)
set #startdate = '1-Mar-2014'
set #enddate = '1-Aug-2014'
;with cte (StartDate, EndDate) as
(
select min(#startdate) StartDate, max(#enddate) EndDate
union all
select dateadd(mm, 1, StartDate), EndDate
from cte
where StartDate < EndDate
)
select StartDate
into #tempDates
from cte
select #cols = STUFF((SELECT distinct ',' + QUOTENAME(convert(CHAR(10), StartDate, 120))
from #tempDates
FOR XML PATH(''), TYPE
).value('.', 'NVARCHAR(MAX)')
,1,1,'') + ',[Total]'
SET #query = 'select ledger_name,
' + #cols + '
from
(
SELECT
CASE WHEN (GROUPING(ledger_name) = 1) THEN ''Grand Total''
ELSE ledger_name END AS ledger_name,
ISNULL(SUM(amount),0) Amount,
CASE WHEN (GROUPING(StartDate) = 1) THEN ''Total''
ELSE convert(CHAR(10), StartDate, 120) END StartDate
FROM #tempDates d
left join Rs_Ledger_Master AS LM on d.StartDate between '''+convert(varchar(10), #startdate, 120)+''' and '''+convert(varchar(10), #enddate, 120)+'''
LEFT OUTER JOIN RS_Payment_Master AS PM ON PM.ledger_code = LM.ledger_code and month(paid_date) = month(StartDate) and year(paid_date) = year(StartDate)
group by
ledger_name,StartDate WITH ROLLUP
) d
pivot
(
SUM(Amount)
for StartDate in (' + #cols + ')
) p
ORDER BY CASE WHEN ledger_name = ''Grand Total'' THEN 1 END'
execute sp_executesql #query;
drop table #tempDates
I think what you can do is, try to use the ROLLUP option in your inner query, which actually returns addtional row for the SUM(Amount), which you can call as Total and add this column to your column list.
Here is the change what I think you need to do
Add total column at the end of your column list
SET #cols= #cols + ',[Total]'
Add the rollup option to your inner query. Note that, the case statement is required to change the text as total for the row.
DECLARE #cols AS NVARCHAR(MAX),
#query AS NVARCHAR(MAX),
#subtotal AS FLOAT,
#startdate as datetime,
#enddate as datetime
DECLARE #ColumnsRollup AS VARCHAR (MAX)
set #startdate = '1-Mar-2014'
set #enddate = '1-Aug-2014'
;with cte (StartDate, EndDate) as
(
select min(#startdate) StartDate, max(#enddate) EndDate
union all
select dateadd(mm, 1, StartDate), EndDate
from cte
where StartDate < EndDate
)
select StartDate
into #tempDates
from cte
select #cols = STUFF((SELECT distinct ',' + QUOTENAME(convert(CHAR(10), StartDate, 120))
from #tempDates
FOR XML PATH(''), TYPE
).value('.', 'NVARCHAR(MAX)')
,1,1,'') + ',[Total]'
SET #query = 'select ledger_name,
' + #cols + '
from
(
SELECT
ledger_name,
ISNULL(SUM(amount),0) Amount,
CASE WHEN (GROUPING(StartDate) = 1) THEN ''Total''
ELSE convert(CHAR(10), StartDate, 120) END StartDate
FROM #tempDates d
left join Rs_Ledger_Master AS LM on d.StartDate between '''+convert(varchar(10), #startdate, 120)+''' and '''+convert(varchar(10), #enddate, 120)+'''
LEFT OUTER JOIN RS_Payment_Master AS PM ON PM.ledger_code = LM.ledger_code and month(paid_date) = month(StartDate) and year(paid_date) = year(StartDate)
group by
ledger_name,StartDate WITH ROLLUP
) d
pivot
(
SUM(Amount)
for StartDate in (' + #cols + ')
) p
WHERE ledger_name IS NOT NULL
UNION ALL
select ledger_name,
' + #cols + ' FROM
(SELECT ''Grand Total'' AS ledger_name,
ISNULL(SUM(amount),0) Amount,
CASE WHEN (GROUPING(StartDate) = 1) THEN ''Total''
ELSE convert(CHAR(10), StartDate, 120) END StartDate
FROM #tempDates d
left join Rs_Ledger_Master AS LM on d.StartDate between '''+convert(varchar(10), #startdate, 120)+''' and '''+convert(varchar(10), #enddate, 120)+'''
LEFT OUTER JOIN RS_Payment_Master AS PM ON PM.ledger_code = LM.ledger_code and month(paid_date) = month(StartDate) and year(paid_date) = year(StartDate)
group by StartDate WITH ROLLUP
) d
pivot
(
SUM(Amount)
for StartDate in (' + #cols + ')
) p
'
print #query
execute sp_executesql #query;
drop table #tempDates
You need additional union all to get the last summary row
You can refer the following article for using ROLLUP
http://technet.microsoft.com/en-us/library/ms189305(v=sql.90).aspx