I have a list of members of a club together with datetime that they attended the club. They can attend the club several times in a single day. I need to know how many Sundays did each member attend over a given period (regardless how many times within a single Sunday). I have a table that lists each attendance, made up of member number and the attendance datetime.
Eg In this example 13/1 and 20/1 are Sundays
MEMBER ATTENDANCE
12345 13/1/13 09:00
12345 13/1/13 15:00
12345 14/1/13 08:00
56789 13/1/13 10:00
56789 13/1/13 15:00
56789 13/1/13 21:00
56789 14/1/13 10:00
56789 20/1/13 09:00
24680 14/1/13 08:00
24680 15/1/13 07:00
Ideally I would like to see this returned:
MEMBER # OF SUNDAYS
12345 1
56789 2
24680 0
I think you need this:
select Member,
count(distinct dateadd(day, datediff(day, 0, Attendance), 0)) as NumberOfSundays
from t
where datepart(dw, Attendance) = 6
group by Member ;
The complicated count is really doing:
count(distinct cast(Attendance as date))
but the date data type is not supported in SQL Server 2005.
EDIT:
Instead of datepart(dw, Attendance) = 6, you can use datename(dw, Attendance) = 'Sunday'.
Try this
SELECT MEMBER,
SUM(CASE DATENAME(dw,ATTENDANCE) WHEN 'Sunday' THEN 1 ELSE 0 END) As [# OF SUNDAYS]
FROM MemberTable
WHERE ATTENDANCE between [YourStartDateAndTime] AND [YourEndDateAndTime] -- replace [YourStartDateAndTime] AND [YourEndDateAndTime] with your value or variable
GROUP BY MEMBER
Take a look into this example, it may work also:
select Member
, count( case when datepart( dw, Attendance ) = 6 then 1 else 0 end ) NumberOfSundays
from YourTable
where Attendance between '2013-01-13' and '2013-01-20'
group by Member
Avoid use functions on your where clause that'll modify the original value of the field. By doing this, SQL Server will create an execution plan using a Table Scan, ignoring any index that would speed up your query!
Related
Hi have records entered into a table, I want to get the hours worked between rows.
id memberid dayname datesigned orderinout
310 987654321 Friday 2021-08-13 09:22:42 1
311 987654321 Friday 2021-08-13 10:15:50 2
312 987654321 Friday 2021-08-13 10:20:00 3
313 987654321 Friday 2021-08-13 12:36:15 4
314 987654321 Friday 2021-08-13 13:01:55 5
315 987654321 Friday 2021-08-13 18:55:41 6
Ideally I would like to work select a member and get the date signed, easy. then do a datediff to work out the hh:mm:ss difference. all good with 2 dates but multi on the same day? little stuck.
SELECT TIMEDIFF(MAX(datesigned),MIN(datesigned)) AS HoursIn
WHERE memberid = '987654321'
AND dayname = 'Friday'
when the date is saved, it will assign a number, first record will be 1 and so on for the member and the date.
so need to get the results for 1+2 then 3+4, 5+6 so on. might even be an odd one.
Any suggestions as im totally lost.
Use the LAG function to achieve the next record. Arrange the columns using orderinout and access the next row with the LAG function. 1 and 2 , 3 and 4 and .............
The TIMEDIFF function exists in mysql, and assuming your database management system is mysql, the following code.
in mysql
SELECT
id,
memberid,
dayname,
datesigned,
orderinout,
TIMEDIFF(datesigned,lag(datesigned,1) over(partition by memberid order by orderinout)) as HoursIn
from t
WHERE memberid = '987654321'
AND dayname = 'Friday'
demo in db<>fiddle
in sql-server
SELECT
id,
memberid,
dayname,
datesigned,
orderinout,
CONVERT (TIME, datesigned - lag(datesigned,1) over(partition by memberid order by orderinout)) as HoursIn
from t
WHERE memberid = '987654321'
AND dayname = 'Friday'
demo in db<>fiddle
If you want to calculate for all members and every day, use the LAG function as follows.
lag(datesigned,1) over(partition by memberid,dayname order by orderinout)
full query
SELECT
id,
memberid,
dayname,
datesigned,
orderinout,
TIMEDIFF(datesigned,lag(datesigned,1) over(partition by memberid,dayname order by orderinout)) as HoursIn
from t
I have a table that holds an employee's leave. If an employee takes more than 1 day off in a row for example 22-05-2020 to the 26-05-2020 this will be displayed as one record. I am trying to get this displayed as 5 records, one for each day they were off.
My table is called: Emp_Annual_Leave
and has the following fields
emp_no leave_type leave_year half_day start_date end_date days_of_leave
12345 Annual 2020 N 22/05/2020 26/05/2020 5
above is how it is currently displayed and I am trying to display the above record like below:
emp_no leave_type leave_year half_day start_date end_date days_of_leave leave_date
12345 Annual 2020 N 22/05/2020 26/05/2020 1 22/05/2020
12345 Annual 2020 N 22/05/2020 26/05/2020 1 23/05/2020
12345 Annual 2020 N 22/05/2020 26/05/2020 1 24/05/2020
12345 Annual 2020 N 22/05/2020 26/05/2020 1 25/05/2020
12345 Annual 2020 N 22/05/2020 26/05/2020 1 26/05/2020
Does anyone know I would go about doing this? I have a feeling I need to use ROW_NUMBER() OVER(PARTITION BY) but any attempts I have made haven't worked well for me.
Thanks in advance,
EDIT:
the table I need to create here is a subquery in a bigger query and needs to be joined back to other queries and tables in my DB. I didn't include this as part of my original question, updated to include now incase this impacts the methods I need to use
You could use a recursive query:
with cte as (
select emp_no, leave_type, leave_year, half_day, start_date, end_date, days_of_leave, start_date as leave_date from emp_annual_leave
union all
select emp_no, leave_type, leave_year, half_day, start_date, end_date, days_of_leave, dateadd(day, 1, leave_date)
from cte
where leave_date < end_date
)
select * from cte
If a given leave may span over more than 100 days, you need to add option (maxrecursion 0) at the end of the query.
I am currently coding an existing Payroll system and I have the below problem. I need to count the Vacation days taken of one employee in one year in order to transfer them to the next. The days can be either complete, or hours in a day (e.g. 6 hour vacation from default 8 hour working day)
However the existing functionality only stores the aforementioned data in a table with columns like this.
EmployeeID | StartDate | EndDate | Hours
1 01-02-2018 04-02-2018 24
1 08-03-2018 08-03-2018 4
2 30-12-2017 04-01-2018 48
3 30-12-2018 04-01-2019 48
Now the issue is that I want to limit the dates to the previous year only. So since we have 2019, I need vacations only from 2018. Meaning records with different Start and End Year, need special handling
The result table should look like this
EmployeeID | HoursPreviousYear
1 28
2 32
3 16
I am already aware of some helpful SQL functions such as DATEDIFF() or YEAR(), but since each record is different, I would probably need to use a cursor and iterate the table. Then to pass the results to a different table, I would have create in the query and return it.
To be honest I am baffled...
I never had to use cursors before and as far as I can see, I am not sure even if I can return a table as a result (which I also need to use in a join later on). I am not sure if it is worth to continue struggling with it, but it seems that there should be an easier way.
My other option was to change the behavior of the Save button, to save 2 different records, with no overlapping years, but I cannot since we are having legacy data...
There are obviously some edge cases where this isn't thorough enough, but it should get you started.
This assumes 8 hours taken per day off, totally fails to account for date ranges that span a weekend or holiday, and wouldn't account for someone taking, say three full days off followed by a half day.
DECLARE #Year int = 2018;
SELECT
EmployeeID,
SUM(CASE WHEN StartDate < DATEFROMPARTS(#Year,1,1)
THEN DATEDIFF(DAY,DATEFROMPARTS(#Year-1,12,31),EndDate)*8
WHEN EndDate > DATEFROMPARTS(#Year,12,31)
THEN DATEDIFF(DAY,StartDate,DATEFROMPARTS(#Year+1,1,1))*8
ELSE [Hours]
END) AS HoursPreviousYear
FROM
#table
GROUP BY
EmployeeID;
+------------+-------------------+
| EmployeeID | HoursPreviousYear |
+------------+-------------------+
| 1 | 28 |
| 2 | 32 |
| 3 | 16 |
+------------+-------------------+
You can use DATEDIFF to calculate additional days for start and end date to deduct extra hours from total hours as shown in the following query-
SELECT EmployeeID,
SUM(Hours) - (SUM(StDiff)+SUM(EndDiff))*8 HoursPreviousYear
FROM
(
SELECT EmployeeID,
CONVERT(DATE, StartDate , 103) StartDate,
CONVERT(DATE, EndDate , 103) EndDate,
Hours,
CASE
WHEN YEAR(CONVERT(DATE, StartDate , 103)) = 2018 THEN 0
ELSE DATEDIFF(DD,CONVERT(DATE, StartDate , 103),CONVERT(DATE, '01-01-2018' , 103))
END StDiff,
CASE
WHEN YEAR(CONVERT(DATE, EndDate , 103)) = 2018 THEN 0
ELSE DATEDIFF(DD,CONVERT(DATE, '31-12-2018' , 103),CONVERT(DATE, EndDate , 103))
END EndDiff
FROM your_table
WHERE YEAR(CONVERT(DATE, StartDate , 103)) <= 2018
AND YEAR(CONVERT(DATE, EndDate , 103)) >= 2018
)A
GROUP BY EmployeeID
I have a table like
person type date
Tom day 4/1/2018
Tom night 3/2/2018
Tom rest 4/3/2018
Jack day 4/1/2018
Jack day 4/2/2018
Jack night 4/3/2018
Peter day 4/1/2018
Peter day 3/2/2018
Peter day 4/3/2018
I want to count each one's working hours in April. Day shift is 8 hours and night is 11 hours. so the result is like
Person hours
Tom 8
Jack 27
Peter 16
I tried a SQL like
select person,count(Type),
case type when 'day' then count(type)*8 when 'night' then count(type)*11
from table where date>'3/30/2018'
group by person,type
and it work
then I try to treat it like a table and add a group by outside like
select *
from (select person,count(Type),
case type when 'day' then count(type)*8 when 'night' then count(type)*11
from table where date>'3/30/2018' group by person,type)
and it doesn't work. Why? any help apppreciated.
You could use the following case-when to convert the type to the corrisponding number of hours:
case
when type='day' then 8
when type='night' then 11
end
then you can just sum the corresponding number of hours:
select
person,
sum(
case
when type='day' then 8
when type='night' then 11
end
) as hours
from
table_name
where
date>='4/01/2018' and date<'5/01/2018'
group by
person
try this:
SELECT person,
SUM(Case WHEN type='day' THEN 8
WHEN type='night' THEN 11
ELSE 0 END)
FROM Table1
WHERE [date]>'2018/03/30'
Group by person
SQL Fiddle: http://sqlfiddle.com/#!18/5b946/1
The key to get your result is to use case statement to "convert" type to appropriate amount of hours. Try this:
select person, SUM([hrs]), [date] from (
select person,
case [TYPE_ID] when 'day' then 8
when 'night' then 11
else 0 end [hrs],
[date]
from MY_TABLE
where date between '4/01/2018' and '5/01/2018'
) [a] group by person
I have a list of members of a club together with dates that they attended the club. I need to know how many Sundays did each member attend over a given period. I have a table that lists each attendance, made up of member number and the attendance date.
Eg In this example 13/1 and 20/1 are Sundays
MEMBER ATTENDANCE
12345 13/1/13
12345 14/1/13
56789 13/1/13
56789 14/1/13
56789 20/1/13
24680 14/1/13
24680 15/1/13
Ideally I would like to see this returned:
MEMBER # OF SUNDAYS
12345 1
56789 2
24680 0
select MEMBER,
sum(case when datename(weekday,ATTENDANCE)='Sunday' then 1 else 0 end) as no_of_sundays
from table
group by MEMBER
EDIT : To handle duplicate dates, use
select MEMBER,
sum(case when datename(weekday,ATTENDANCE)='Sunday' then 1 else 0 end) as no_of_sundays
from (select distinct MEMBER,ATTENDANCE from table ) as t
group by MEMBER