How do I create a series of specific days in a SQL table? - sql

I have a table called CLASSTIMES that has a column of type bool for each day of the week (SUNDAY,MONDAY,TUESDAY...etc) and also contains a STARTDATE and an ENDDATE column. For example, I would have a row that has MONDAY and WEDNESDAY selected with a STARTDATE of June 3, 2013 and an ENDDATE of June 26, 2013.
What I'd like to be able to do is create a SPROC to insert a series of rows into a table called CLASSCALENDAR that contains all of dates between the StartDate and EndDate for each selected day column.
For example, if the user selected Monday and Wednesay from the ClassTimes table, it would generate:
Row Date
1 2013-06-03
2 2013-06-10
3 2013-06-17
4 2013-06-24
5 2013-06-05
6 2013-06-12
7 2013-06-19
8 2013-06-26
I have tried to set this up but it is a bit over my head. Any help would be much appreciated.

Here's an SQL statement that might work for you.
SELECT course,
Convert(varchar(25), course_date, 101) AS course_date
FROM (SELECT course_no AS course,
DATEADD(dd, rn-1, startdate) AS course_date,
DATENAME(dw, DATEADD(dd, rn-1, startdate)) AS dow
FROM (SELECT row_number() OVER (ORDER BY c1) AS rn
FROM dummy) sub1,
classtimes
WHERE rn <= (DATEDIFF(dd, startdate, enddate)+1)
) list_of_dates,
(SELECT course_no,
(CASE monday WHEN 1 THEN 'Monday' END) AS dow
FROM classtimes
UNION
SELECT course_no,
(CASE tuesday WHEN 1 THEN 'Tuesday' END)
FROM classtimes
UNION
SELECT course_no,
(CASE wednesday WHEN 1 THEN 'Wednesday' END)
FROM classtimes
UNION
SELECT course_no,
(CASE thursday WHEN 1 THEN 'Thursday' END)
FROM classtimes
UNION
SELECT course_no,
(CASE friday WHEN 1 THEN 'Friday' END)
FROM classtimes
UNION
SELECT course_no,
(CASE saturday WHEN 1 THEN 'Saturday' END)
FROM classtimes
UNION
SELECT course_no,
(CASE sunday WHEN 1 THEN 'Sunday' END)
FROM classtimes
) class_days
WHERE list_of_dates.dow = class_days.dow
AND list_of_dates.course = class_days.course_no
ORDER BY course_no,
course_date
I used the query
SELECT course_no AS course,
DATEADD(dd, rn-1, startdate) AS course_date,
DATENAME(dw, DATEADD(dd, rn-1, startdate)) AS dow
FROM (SELECT row_number() OVER (ORDER BY c1) AS rn
FROM dummy) sub1,
classtimes
WHERE rn <= (DATEDIFF(dd, startdate, enddate)+1)
to generate a list of all dates between the startdate and enddate for each course. In order for this query to work correctly, the dummy table must contain at least as many rows as the number of days between the startdate and enddate for each course. So the result of this is a list of days between the startdate and enddate for each course, along with the day of week for that date.
| COURSE | COURSE_DATE | DOW |
------------------------------------
| MATH | 06/03/2013 | Monday |
| MATH | 06/04/2013 | Tuesday |
| MATH | 06/05/2013 | Wednesday |
| MATH | 06/06/2013 | Thursday |
| MATH | 06/07/2013 | Friday |
.........
.........
| MATH | 06/24/2013 | Monday |
| MATH | 06/25/2013 | Tuesday |
| MATH | 06/26/2013 | Wednesday |
I then have a subquery that uses a series of UNIONs to take the day of week columns from the classtimes table and generate the days of the week the classes are to be held. I then just join list_of_dates subquery with the class_days subquery to get the dates the classes are to be held.
| COURSE | COURSE_DATE |
-------------------------
| MATH | 06/03/2013 |
| MATH | 06/05/2013 |
| MATH | 06/10/2013 |
| MATH | 06/12/2013 |
| MATH | 06/17/2013 |
| MATH | 06/19/2013 |
| MATH | 06/24/2013 |
| MATH | 06/26/2013 |
I'm sure there's a more efficient/elegant way to generate the list of the days of the week for the class from the classtimes table (the class_days subquery), but I couldn't think of one.

Related

Full calendar months between two dates

I have two dates (let's say 2020-09-15 and 2020-12-10) in a SQL Server database and I need to find out how many full calendar months exist between both dates.
In my example the output should be "2" as there October and November are the only full calendar months.
Thanks in advance!
You could do this:
select t.*,
datediff(month, start_date, end_date)
- case when day(end_date) < day(start_date) then 1 else 0 end
as month_diff
from mytable t
datediff() counts the number of end of month boundaries that exist within the two dates. We can then adjust the result by substracting 1 if the day of the month of the end date is less than that of the start date.
Demo on DB Fiddle:
select t.*,
datediff(month, start_date, end_date)
- case when day(end_date) < day(start_date) then 1 else 0 end
as month_diff
from (values
('2020-09-15', '2020-12-10'),
('2020-09-15', '2020-12-17')
) t(start_date, end_date)
start_date | end_date | month_diff
:--------- | :--------- | ---------:
2020-09-15 | 2020-12-10 | 2
2020-09-15 | 2020-12-17 | 3
Use SQL Server's datetime functions to check if date1 is the first day of the month or not and if date2 is the last day of the month or not, so you can calculate the difference:
WITH cte(date1, date2) AS (
SELECT '2020-09-15', '2020-12-10' UNION ALL
SELECT '2020-09-01', '2020-12-10' UNION ALL
SELECT '2020-09-15', '2020-12-31' UNION ALL
SELECT '2020-09-15', '2020-10-31' UNION ALL
SELECT '2020-09-15', '2020-09-30' UNION ALL
SELECT '2020-09-01', '2020-09-30'
)
SELECT *,
DATEDIFF(
MONTH,
CASE DAY(date1)
WHEN 1 THEN DATEADD(DAY, -1, date1)
ELSE EOMONTH(date1)
END,
CASE
WHEN DAY(date2) = DAY(EOMONTH(date2)) THEN date2
ELSE DATEADD(MONTH, -1, EOMONTH(date2))
END
) diff_in_full_months
FROM cte
See the demo.
Results:
> date1 | date2 | diff_in_full_months
> :--------- | :--------- | ------------------:
> 2020-09-15 | 2020-12-10 | 2
> 2020-09-01 | 2020-12-10 | 3
> 2020-09-15 | 2020-12-31 | 3
> 2020-09-15 | 2020-10-31 | 1
> 2020-09-15 | 2020-09-30 | 0
> 2020-09-01 | 2020-09-30 | 1

SQL to get a row for start and end date for each year given a start date and number of years

I have the following data in a SQL table:
+------------------------------------+
| ID YEARS START_DATE |
+------------------------------------+
| ----------- ----------- ---------- |
| 1 5 2020-12-01 |
| 2 8 2020-12-01 |
+------------------------------------+
Trying to create a SQL that would expand the above data and give me a start and end date for each year depending on YEARS and START_DATE from above table. Sample output below:
+-----------------------------------------------+
| ID YEAR DATE_START DATE_END |
+-----------------------------------------------+
| ----------- ----------- ---------- ---------- |
| 1 1 2020-12-01 2021-11-30 |
| 1 2 2021-12-01 2022-11-30 |
| 1 3 2022-12-01 2023-11-30 |
| 1 4 2023-12-01 2024-11-30 |
| 1 5 2024-12-01 2025-11-30 |
| 2 1 2020-12-01 2021-11-30 |
| 2 2 2021-12-01 2022-11-30 |
| 2 3 2022-12-01 2023-11-30 |
| 2 4 2023-12-01 2024-11-30 |
| 2 5 2024-12-01 2025-11-30 |
| 2 6 2025-12-01 2026-11-30 |
| 2 7 2026-12-01 2027-11-30 |
| 2 8 2027-12-01 2028-11-30 |
+-----------------------------------------------+
I would use an inline tally for this, as they are Far faster than a recursive CTE solution. Assuming you have low values for Years:
WITH YourTable AS(
SELECT *
FROM (VALUES(1,5,CONVERT(date,'20201201')),
(2,8,CONVERT(date,'20201201')))V(ID,Years, StartDate))
SELECT ID,
V.I + 1 AS [Year],
DATEADD(YEAR, V.I, YT.StartDate) AS StartDate,
DATEADD(DAY, -1, DATEADD(YEAR, V.I+1, YT.StartDate)) AS EndDate
FROM YourTable YT
JOIN (VALUES(0),(1),(2),(3),(4),(5),(6),(7),(8),(9),(10))V(I) ON YT.Years > V.I;
If you have more than 10~ years you can use either create a tally table, or create an large one inline in a CTE. This would start as:
WITH N AS(
SELECT N
FROM (VALUES(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL))N(N)),
Tally AS(
SELECT ROW_NUMBER() OVER (ORDER BY (SELECT NULL)) -1 AS I --remove the -1 if you don't want to start from 0
FROM N N1, N N2) --100 rows, add more Ns for more rows
...
Of course, I doubt you have 1,000 of years of data.
You can use a recursive CTE:
with cte as (
select id, 1 as year, start_date,
dateadd(day, -1, dateadd(year, 1, start_date)) as end_date,
years as num_years
from t
union all
select id, year + 1, dateadd(year, 1, start_date),
dateadd(day, -1, dateadd(year, 1, start_date)) as end_date,
num_years
from cte
where year < num_years
)
select id, year, start_date, end_date
from cte;
Here is a db<>fiddle.
In a query, you can use the following:
DATEADD(YEAR, 1, DATE_START) - 1
to add this to the table you can just create the extra column, and set it equal to the value of the above, e.g.
UPDATE MyTable
SET DATE_END = DATEADD(YEAR, 1, DATE_START) - 1
If you are working with sql server, then you can try to use operator CROSS APPLY with master.dbo.spt_values table to get list of numbers and generate dates:
select ID,T.number+1 as YEAR,
--generate date_start using T.number
dateadd(year,T.number,START_DATE)date_start,
--generate end_date: adding 1 year to start date
dateadd(dd,-1,dateadd(year,1,dateadd(year,T.number,START_DATE)))date_end
from Table
cross apply
master.dbo.spt_values T
where T.type='P' and T.number<YEARS

How to return same row multiple times with multiple conditions

My knowledge is pretty basic so your help would be highly appreciated.
I'm trying to return the same row multiple times when it meets the condition (I only have access to select query).
I have a table of more than 500000 records with Customer ID, Start Date and End Date, where end date could be null.
I am trying to add a new column called Week_No and list all rows accordingly. For example if the date range is more than one week, then the row must be returned multiple times with corresponding week number. Also I would like to count overlapping days, which will never be more than 7 (week) per row and then count unavailable days using second table.
Sample data below
t1
ID | Start_Date | End_Date
000001 | 12/12/2017 | 03/01/2018
000002 | 13/01/2018 |
000003 | 02/01/2018 | 11/01/2018
...
t2
ID | Unavailable
000002 | 14/01/2018
000003 | 03/01/2018
000003 | 04/01/2018
000003 | 08/01/2018
...
I cannot pass the stage of adding week no. I have tried using CASE and UNION ALL but keep getting errors.
declare #week01start datetime = '2018-01-01 00:00:00'
declare #week01end datetime = '2018-01-07 00:00:00'
declare #week02start datetime = '2018-01-08 00:00:00'
declare #week02end datetime = '2018-01-14 00:00:00'
...
SELECT
ID,
'01' as Week_No,
'2018' as YEAR,
Start_Date,
End_Date
FROM t1
WHERE (Start_Date <= #week01end and End_Date >= #week01start)
or (Start_Date <= #week01end and End_Date is null)
UNION ALL
SELECT
ID,
'02' as Week_No,
'2018' as YEAR,
Start_Date,
End_Date
FROM t1
WHERE (Start_Date <= #week02end and End_Date >= #week02start)
or (Start_Date <= #week02end and End_Date is null)
...
The new table should look like this
ID | Week_No | Year | Start_Date | End_Date | Overlap | Unavail_Days
000001 | 01 | 2018 | 12/12/2017 | 03/01/2018 | 3 |
000002 | 02 | 2018 | 13/01/2018 | | 2 | 1
000003 | 01 | 2018 | 02/01/2018 | 11/01/2018 | 6 | 2
000003 | 02 | 2018 | 02/01/2018 | 11/01/2018 | 4 | 1
...
business wise i cannot understand what you are trying to achieve. You can use the following code though to calculate your overlapping days etc. I did it the way you asked, but i would recommend a separate table, like a Time dimension to produce a "cleaner" solution
/*sample data set in temp table*/
select '000001' as id, '2017-12-12'as start_dt, ' 2018-01-03' as end_dt into #tmp union
select '000002' as id, '2018-01-13 'as start_dt, null as end_dt union
select '000003' as id, '2018-01-02' as start_dt, '2018-01-11' as end_dt
/*calculate week numbers and week diff according to dates*/
select *,
DATEPART(WK,start_dt) as start_weekNumber,
DATEPART(WK,end_dt) as end_weekNumber,
case
when DATEPART(WK,end_dt) - DATEPART(WK,start_dt) > 0 then (DATEPART(WK,end_dt) - DATEPART(WK,start_dt)) +1
else (52 - DATEPART(WK,start_dt)) + DATEPART(WK,end_dt)
end as WeekDiff
into #tmp1
from
(
SELECT *,DATEADD(DAY, 2 - DATEPART(WEEKDAY, start_dt), CAST(start_dt AS DATE)) [start_dt_Week_Start_Date],
DATEADD(DAY, 8 - DATEPART(WEEKDAY, start_dt), CAST(start_dt AS DATE)) [startdt_Week_End_Date],
DATEADD(DAY, 2 - DATEPART(WEEKDAY, end_dt), CAST(end_dt AS DATE)) [end_dt_Week_Start_Date],
DATEADD(DAY, 8 - DATEPART(WEEKDAY, end_dt), CAST(end_dt AS DATE)) [end_dt_Week_End_Date]
from #tmp
) s
/*cte used to create duplicates when week diff is over 1*/
;with x as
(
SELECT TOP (10) rn = ROW_NUMBER() --modify the max you want
OVER (ORDER BY [object_id])
FROM sys.all_columns
ORDER BY [object_id]
)
/*final query*/
select --*
ID,
start_weekNumber+ (r-1) as Week,
DATEPART(YY,start_dt) as [YEAR],
start_dt,
end_dt,
null as Overlap,
null as unavailable_days
from
(
select *,
ROW_NUMBER() over (partition by id order by id) r
from
(
select d.* from x
CROSS JOIN #tmp1 AS d
WHERE x.rn <= d.WeekDiff
union all
select * from #tmp1
where WeekDiff is null
) a
)a_ext
order by id,start_weekNumber
--drop table #tmp1,#tmp
The above will produce the results you want except the overlap and unavailable columns. Instead of just counting weeks, i added the number of week in the year using start_dt, but you can change that if you don't like it:
ID Week YEAR start_dt end_dt Overlap unavailable_days
000001 50 2017 2017-12-12 2018-01-03 NULL NULL
000001 51 2017 2017-12-12 2018-01-03 NULL NULL
000001 52 2017 2017-12-12 2018-01-03 NULL NULL
000002 2 2018 2018-01-13 NULL NULL NULL
000003 1 2018 2018-01-02 2018-01-11 NULL NULL
000003 2 2018 2018-01-02 2018-01-11 NULL NULL

SQL: Generate Record Per Month In Date Range

I have a table which describes a value which is valid for a certain period of days / months.
The table looks like this:
+----+------------+------------+-------+
| Id | From | To | Value |
+----+------------+------------+-------+
| 1 | 2018-01-01 | 2018-03-31 | ValA |
| 2 | 2018-01-16 | NULL | ValB |
| 3 | 2018-04-01 | 2018-05-12 | ValC |
+----+------------+------------+-------+
As you can see, the only value still valid on this day is ValB (To is nullable, From isn't).
I am trying to achieve a view on this table like this (assuming I render this view someday in july 2018):
+----------+------------+------------+-------+
| RecordId | From | To | Value |
+----------+------------+------------+-------+
| 1 | 2018-01-01 | 2018-01-31 | ValA |
| 1 | 2018-02-01 | 2018-02-28 | ValA |
| 1 | 2018-03-01 | 2018-03-31 | ValA |
| 2 | 2018-01-16 | 2018-01-31 | ValB |
| 2 | 2018-02-01 | 2018-02-28 | ValB |
| 2 | 2018-03-01 | 2018-03-31 | ValB |
| 2 | 2018-04-01 | 2018-04-30 | ValB |
| 2 | 2018-05-01 | 2018-05-31 | ValB |
| 2 | 2018-06-01 | 2018-06-30 | ValB |
| 3 | 2018-04-01 | 2018-04-30 | ValC |
| 3 | 2018-05-01 | 2018-05-12 | ValC |
+----------+------------+------------+-------+
This view basically creates a record for each record in the table, but splitted by month, using the correct dates (especially minding the start and end dates that are not on the first or the last day of the month).
The one record without a To date (so it's still valid to this day), is rendered until the last day of the month in which I render the view, so at the time of writing, this is july 2018.
This is a simple example, but a solution will seriously help me along. I'll need this for multiple calculations, including proration of amounts.
Here's a table script and some insert statements that you can use:
CREATE TABLE [dbo].[Test]
(
[Id] INT IDENTITY(1,1) NOT NULL PRIMARY KEY,
[From] SMALLDATETIME NOT NULL,
[To] SMALLDATETIME NULL,
[Value] NVARCHAR(100) NOT NULL
)
INSERT INTO dbo.Test ([From],[To],[Value])
VALUES
('2018-01-01','2018-03-31','ValA'),
('2018-01-16',null,'ValB'),
('2018-04-01','2018-05-12','ValC');
Thanks in advance!
Generate all months that might appear on your values (with start and end), then join where each month overlaps the period of your values. Change the result so if a month doesn't overlap fully, you just display the limits of your period.
DECLARE #StartDate DATE = '2018-01-01'
DECLARE #EndDate DATE = '2020-01-01'
;WITH GeneratedMonths AS
(
SELECT
StartDate = #StartDate,
EndDate = EOMONTH(#StartDate)
UNION ALL
SELECT
StartDate = DATEADD(MONTH, 1, G.StartDate),
EndDate = EOMONTH(DATEADD(MONTH, 1, G.StartDate))
FROM
GeneratedMonths AS G
WHERE
DATEADD(MONTH, 1, G.StartDate) < #EndDate
)
SELECT
T.Id,
[From] = CASE WHEN T.[From] >= G.StartDate THEN T.[From] ELSE G.StartDate END,
[To] = CASE WHEN G.EndDate >= T.[To] THEN T.[To] ELSE G.EndDate END,
T.Value
FROM
dbo.Test AS T
INNER JOIN GeneratedMonths AS G ON
G.EndDate >= T.[From] AND
G.StartDate <= ISNULL(T.[To], GETDATE())
ORDER BY
T.Id,
G.StartDate
OPTION
(MAXRECURSION 3000)
Recursive cte is very simple way if you don't have a large dataset :
with t as (
select id, [from], [to], Value
from Test
union all
select id, dateadd(mm, 1, [from]), [to], value
from t
where dateadd(mm, 1, [from]) < coalesce([to], getdate())
)
select id, [from], (case when eomonth([from]) <= coalesce([to], cast(getdate() as date))
then eomonth([from]) else coalesce([to], eomonth([from]))
end) as [To],
Value
from t
order by id;
By using date functions and recursive CTE.
with cte as
(
Select Id, Cast([From] as date) as [From], EOMONTH([from]) as [To1],
COALESCE([To],EOMONTH(GETDATE())) AS [TO],Value from test
UNION ALL
Select Id, DATEADD(DAY,1,[To1]),
CASE when EOMONTH(DATEADD(DAY,1,[To1])) > [To] THEN CAST([To] AS DATE)
ELSE EOMONTH(DATEADD(DAY,1,[To1])) END as [To1],
[To],Value from cte where TO1 <> [To]
)
Select Id, [From],[To1] as [To], Value from cte order by Id
#EzLo your solution is good but require setting 2 variables with fixed values.
To avoid this you can do recursive CTE on real data
WITH A AS(
SELECT
T.Id, CAST(T.[From] AS DATE) AS [From], CASE WHEN T.[To]<EOMONTH(T.[From], 0) THEN T.[To] ELSE EOMONTH(T.[From], 0) END AS [To], T.Value, CAST(0 AS INTEGER) AS ADD_M
FROM
TEST T
UNION ALL
SELECT
T.Id, DATEADD(DAY, 1, EOMONTH(T.[From], -1+(A.ADD_M+1))), CASE WHEN T.[To]<EOMONTH(T.[From], A.ADD_M+1) THEN T.[To] ELSE EOMONTH(T.[From], A.ADD_M+1) END AS [To], T.Value, A.ADD_M+1
FROM
TEST T
INNER JOIN A ON T.Id=A.Id AND DATEADD(MONTH, A.ADD_M+1, T.[From]) < CASE WHEN T.[To] IS NULL THEN CAST(GETDATE() AS DATE) ELSE T.[To] END
)
SELECT
A.[Id], A.[From], A.[To], A.[Value]
FROM
A
ORDER BY A.[Id], A.[From]

SQL - Conditional column selection in join

I am not sure if this scenario can be achieved using TSQL. I have a table called WorkingDays, which have this info
ID | EmployeeId | Monday | Tuesday | Wednesday | Thursday | Friday
----------------------------------------------------------------------
1 | 1 | 2 | 2 | 3 | 6 | 5
2 | 2 | 1 | 7 | 5 | 2 | 3
The days columns store Ids of WorkingSchedule table, which has this columns:
ID int Primary Key
StartTime time
EndTime time
So what I need id get the StartTime and EndTime of an employee depending on the current date.
What I need to get from query is the start and end time depending on the day. The day I want to filter is de current date (using getdate() function)
So need to select the correct day column name to make the join.
How can I achieve this scenario?
The dynamic sql version:
declare #sql nvarchar(max) ='
select
t.EmployeeId
, StarTime = max(case when t.rn=1 then '+quotename(datename(weekday,getdate()))+' end)
, EndTime = max(case when t.rn=2 then '+quotename(datename(weekday,getdate()))+' end)
from (
select *
, rn = row_number() over (partition by t.EmployeeId order by t.Id)
from t
) t
group by t.EmployeeId;'
exec sp_executesql #sql;
rextester demo: http://rextester.com/WNH34961
returns:
+------------+----------+---------+
| EmployeeId | StarTime | EndTime |
+------------+----------+---------+
| 1 | 5 | 3 |
+------------+----------+---------+
Depending on how you want the output, here are two other ways that do not use dynamic sql:
Both use cross apply() to unpivot the data, and WorkDay = datename(weekday,getdate()) to get the current WorkDay column.
For one row output we add some conditional aggregation:
/* one row per employeeId */
select
t.EmployeeId
, x.WorkDay
, StarTime = max(case when t.rn=1 then x.Time end)
, EndTime = max(case when t.rn=2 then x.Time end)
from (
select *
, rn = row_number() over (partition by t.EmployeeId order by t.Id)
from t
) t
cross apply (values
('Monday',Monday),('Tuesday',Tuesday),('Wednesday',Wednesday)
,('Thursday',Thursday),('Friday',Friday)
) x (WorkDay,Time)
where WorkDay = datename(weekday,getdate())
group by t.EmployeeId, x.WorkDay
returns:
+------------+---------+----------+---------+
| EmployeeId | WorkDay | StarTime | EndTime |
+------------+---------+----------+---------+
| 1 | Friday | 5 | 3 |
+------------+---------+----------+---------+
If you want the output on two rows, like your current output:
/* two rows per employeeId */
select
t.Id
, t.EmployeeId
, x.WorkDay
, t.StartEnd
, x.Time
from (
select *
, StartEnd = case
when row_number() over (partition by t.EmployeeId order by t.Id) = 1
then 'StartTime'
else 'EndTime'
end
from t
) t
cross apply (values
('Monday',Monday),('Tuesday',Tuesday),('Wednesday',Wednesday)
,('Thursday',Thursday),('Friday',Friday)
) x (WorkDay,Time)
where WorkDay = datename(weekday,getdate());
returns:
+----+------------+---------+-----------+------+
| Id | EmployeeId | WorkDay | StartEnd | Time |
+----+------------+---------+-----------+------+
| 1 | 1 | Friday | StartTime | 5 |
| 2 | 1 | Friday | EndTime | 3 |
+----+------------+---------+-----------+------+
select wd.Employee, ws.StartTime, ws.EndTime
from WorkingDays wd
join WorkingSchedule ws on ws.Id = case datename(weekday, getdate())
when 'Monday' then ws.Monday
when 'Tuesday' then ws.Tuesday
when 'Wednesday' then ws.Wednesday
when 'Thursday' then ws.Thursday
when 'Friday' then ws.Friday
else 0
end
Hint: datename(weekday, getdate()) returns you the weekday name in your current locale! This might be better:
select wd.Employee, ws.StartTime, ws.EndTime
from WorkingDays wd
join WorkingSchedule ws on ws.Id = case datepart(weekday, getdate())
when 1 then wd.Monday
when 2 then wd.Tuesday
when 3 then wd.Wednesday
when 4 then wd.Thursday
when 5 then wd.Friday
else 0
end
But then you have to check which day is the first of week (0, 1), depending on your settings.