How to get third Thursday of last month - sql-server

My report generator should get all entries from third Thursday of last month.
How can I achieve This in ms sql server ?

You can use something like this:
WHERE DATEPART(dw,[YourDateColumn]) = 5 -- Thursday
AND DATEPART(d,[YourDateColumn]) BETWEEN 15 AND 21 -- Third thursday in month
AND DATEDIFF(m,GETDATE(),[YourDateColumn])=-1 -- Last month
But you need to be aware that the query could be slow because of the functions.
See also: Avoid Using Function in WHERE Clause. Why?

For something like this is so much easier with a calender table. See
Create a calender date table

The code below finds the third Thursday of last month
(last = previous or last = current? if last = current, substitute dateadd (month, -1, getdate()) with getdate()).
You can wrap it into a function and use in WHERE clause of your query
or calculate it just before filtering using a variable,
so your query will look like
SELECT...WHERE dt >= fn()
or
SELECT...WHERE dt >= #dt
option(recompile)
So indexes(if any) can be used
with nums as -- numbers 1..31
(
select number as n
from master..spt_values
where type = 'p'
and number between 0 and 30
)
, thur as
(
select dt,
dd,
ROW_NUMBER() over (order by dt) as rn
from nums cross apply
(
select cast(convert(char(6), dateadd (month, -1, getdate()), 112) + '01' as date) as dt0 -- the first of last month
)a
cross apply( select dateadd(day, n, dt0) as dt) a1
cross apply( select datename(dw, dt) as dd, month(dt) as mm) a2
where dd = 'Thursday' and mm = month(dt0)
)
select dt
from thur
where rn = 3;

Related

How to get Satuday's date of previous month in SQL Server? Can someone help me with this query?

Suppose now we are in September, I want output of the last Saturday date in the previous month, August, where 28-08-2021 falls under last Saturday of previous month in SQL Server
..fiddle..
select *, datename(weekday, pmlsat), dateadd(week, 1, pmlsat)
from
(
select _date,
--last saturday of previous month
dateadd(day, -datepart(weekday, dateadd(day, ##datefirst, eomonth(_date, -1)))%7, eomonth(_date, -1)) as pmlsat
from
(
select top(100) dateadd(month, row_number() over(order by ##spid), '20141215') as _date
from sys.all_objects
) as d
) as p
order by _date;
DECLARE #date1 DATETIME
SET #date1='2021-8-31'
WHILE Day(#date1) >= 1
BEGIN
IF (SELECT Datename(weekday, #date1)) = 'Saturday'
BREAK
SET #date1=Dateadd(dd, -1, #date1)
CONTINUE
END
SELECT Datename(weekday, #date1) AS 'Datename',
(SELECT CONVERT(NVARCHAR(20), #date1, 23)) AS 'DATE'
First, let's talk about how to get the beginning of this month. There are a multiple ways, I find DATEFROMPARTS() the most intuitive (see Simplify Date Period Calculations in SQL Server):
DECLARE #FirstOfMonth date = DATEFROMPARTS(YEAR(GETDATE()), MONTH(GETDATE()), 1);
SELECT #FirstOfMonth;
-- result:
-- 2021-09-01
Now, the last Saturday in the previous month must be between 1 and 7 days before the first of this month. So we can generate a sequence of 7 consecutive numbers, and subtract those days from the first of the month, like this:
DECLARE #FirstOfMonth date = DATEFROMPARTS(YEAR(GETDATE()), MONTH(GETDATE()), 1);
SELECT #FirstOfMonth;
;WITH n(n) AS
(
SELECT 1 UNION ALL
SELECT n + 1 FROM n WHERE n < 7
)
SELECT d = DATEADD(DAY, -n, #FirstOfMonth) FROM n;
/* result:
2021-08-31
2021-08-30
2021-08-29
2021-08-28
2021-08-27
2021-08-26
2021-08-25 */
To determine what a Saturday is, you either need to rely on DATEPART(WEEKDAY, date) - which in turn is affected by SET DATEFIRST, or you need to rely on DATENAME(WEEKDAY, date) - which in turn is affected by SET LANGUAGE. I will err toward language being more stable (English), so:
DECLARE #FirstOfMonth date = DATEFROMPARTS(YEAR(GETDATE()), MONTH(GETDATE()), 1);
SELECT #FirstOfMonth;
;WITH n(n) AS
(
SELECT 1 UNION ALL
SELECT n + 1 FROM n WHERE n < 7
),
d(d) AS
(
SELECT DATEADD(DAY, -n, #FirstOfMonth)
FROM n
)
SELECT LastMonthLastSaturday = d
FROM d
WHERE DATENAME(WEEKDAY, d) = 'Saturday';
-- result:
-- 2021-08-28
But that is a subjective call - if you can't rely on one of those, get a calendar table, then it's simply something like:
SELECT LastMonthLastSaturday = MAX(TheDate)
FROM dbo.Calendar
WHERE TheDayOfWeekName = 'Saturday'
AND TheDate < DATEFROMPARTS(YEAR(GETDATE()), MONTH(GETDATE()), 1);

List of Employees who are not in the list one day before and one day after weekend

I need list of those employees who are absent one day before and one day after weekend in a week......like if some is absent in Friday and present on Monday should not be included in the list
Use datepart(weekday, ) to fetch all records relative to monday and friday.
Have a look at SET DATEFIRST function too.
select *
from your_table
where datepart(weekday, Date) = 5
or datepart(weekday, Date) = 1;
This will list all employee id that are absent on a Friday and the following Monday (+1 week). I set-up a calendar week from mininum date to maximum date from the table and get only Friday and Monday. Then get all empid that has no attendance in any of those dates.
with caldte as (
SELECT dateadd(day, rn - 1, t.mindte) as dates,
datepart(weekday, dateadd(day, rn - 1, t.mindte)) as weekday,
datepart(wk, dateadd(day, rn - 1, t.mindte)) as weeknum
FROM (
select row_number() OVER ( order by c.object_id ) AS rn
FROM sys.columns c) rns,
(select min(dte) as mindte, max(dte) as maxdte
from tbl) t
WHERE rn - 1 <= datediff(day, t.mindte, t.maxdte)
and datepart(weekday, dateadd(day, rn - 1, t.mindte)) in (2, 6)
)
select distinct empid
from tbl
where empid not in (
select t.empid
from caldte c, tbl t
where c.dates = t.dte)
order by empid

Calculating every month 8th business day

How to get 8th Business day, start checking to see if the data exists. If it does exist Set and represents more than 50% of the loans - Set the Verified Date to that Day
Thank You Regards Shehroz
Declare #D date = '2012-12-01' -- Supply 1st of Month
Select D=max(D)
From (
Select Top 8 D=DateAdd(DD,N,#D)
From (Select N From (Values(0),(1),(2),(3),(4),(5),(6),(7),(8),(9),(10),(11),(12),(13)) N(N) ) A
Where DatePart(DW,DateAdd(DD,N,#D)) between 2 and 6
) A
Returns
2012-12-12
This will give you the result, however my answer lists all 8th business days from specific date.
It does not consider holidays though. With small changes you can consider holidays too.
You can use top 1 on the last select to get only one date.
DECLARE #start date
SELECT #start = '20160101'
;WITH n AS (
SELECT n = ROW_NUMBER() OVER (ORDER BY [object_id])
FROM sys.all_objects
), dates AS (
SELECT DATEADD(DAY, n - 1, #start) Dt
FROM n
), dayNum AS (
SELECT Dt, DATENAME(WEEKDAY, Dt) WeekDayName
, ROW_NUMBER() OVER (ORDER BY Dt) DayNumber
FROM dates
WHERE DATENAME(WEEKDAY, Dt) NOT IN ('Saturday', 'Sunday')
)
SELECT Dt, DATENAME(WEEKDAY, Dt) WeekDayName
FROM dayNum
WHERE DayNumber % 8 = 0
ORDER BY Dt

Select all days of the current week

Good Day! I am working on a chart where I need to display all the days of the current week to show the sales per Week. So far, I am able to display all the days of the current week, I'm just having a trouble in displaying the sales for each day of the week.Since there are no records in the database for the days of the week, it the TOTAL_SALES column should all return a Null value. Instead, it returns the total sales recorded in the database. Here is my Stored Procedure query so far.
WITH DAYSOFTHEWEEK AS
(
SELECT 0 DAY
UNION ALL
SELECT DAY + 1 FROM DAYSOFTHEWEEK WHERE DAY < 6
)
SELECT DATEADD(DAY, DAY, DATEADD(DAY, 2-DATEPART(WEEKDAY, CONVERT (date, GETDATE())), CONVERT (date, GETDATE()))) AS DAY_OF_THE_WEEK,
SUM([ORDER].NET_AMOUNT) AS TOTAL_SALES
FROM DAYSOFTHEWEEK, [ORDER]
GROUP BY DAYSOFTHEWEEK.DAY
I tried adding this condition statement,
WHERE DAYSOFTHEWEEK.DAY IN ([ORDER].ORDER_DATE)
But it returns this error
Operand type clash: date is incompatible with int
Can someone help me out on this?Is there a work around with the code that I already have? Thanks in advance!
What I think you're after is a SUM of each day's sales for the current week with NULL if there are no sales. The secret is to left join your date list onto your data:
-- Setup some fake sales data
WITH TestData(N, Order_Date, Net_Amount) AS (
SELECT 1 N, CAST(GETDATE() AS DATE) Order_Date, RAND() * 100 Net_Amount
UNION ALL
SELECT N+1 N, CAST(GETDATE()-N/5 AS DATE) Order_Date, RAND(CHECKSUM(NEWID())) * 100 Net_Amount FROM TestData
WHERE N < 20
)
SELECT TestData.Order_Date, TestData.Net_Amount INTO #Order FROM TestData
--Set the first day of the week (if required)
SET DATEFIRST 7 --Sunday
;WITH Days(N,DayOfTheWeek) AS (
SELECT 1 N, DATEADD(DAY, 1-DATEPART(WEEKDAY, GETDATE()), CONVERT(DATE,GETDATE())) DayOfTheWeek
UNION ALL
SELECT N+1 N,DATEADD(DAY, 1, DayOfTheWeek) DayOfTheWeek FROM Days
WHERE N < 7
)
SELECT d.DayOfTheWeek, SUM(Net_Amount) TotalAmount
FROM Days d
LEFT JOIN #Order ON d.DayOfTheWeek = Order_Date
GROUP BY d.DayOfTheWeek
DayOfTheWeek TotalAmount
------------ ----------------------
2016-08-07 219.036784917497
2016-08-08 273.319570812461
2016-08-09 271.148114731087
2016-08-10 194.780039228967
2016-08-11 NULL
2016-08-12 NULL
2016-08-13 NULL
Here is every day this week, starting at your datefirst date, which can be temporarily varied for the query with SET DATEFIRST if you need to have some other week start date
I think you have some sales table there that you haven't shown us, you need to join to that on date, then group by
WITH DAYSOFTHEWEEK AS
(
SELECT cast(dateadd(
day,
-datepart(weekday,getdate()) + 1 ,
GETDATE()
)
as date) [DAY], 0 as cnt
UNION ALL
SELECT dateadd(day,1,[DAY]), cnt + 1 FROM DAYSOFTHEWEEK WHERE cnt < 6
)
select DAYSOFTHEWEEK.[day], SUM([ORDER].NET_AMOUNT) AS TOTAL_SALES from daysoftheweek
JOIN
SalesTable on
CAST(SalesTable.SalesDate date) = DAYSOFTHEWEEK.[day]
GROUP BY DAYSOFTHEWEEK.[day]
A little over complicated for me:
To get name of the week use, for example
SELECT DATENAME(dw,getdate())
But you really need something like this:
SELECT ProductName,Sum(Sales) From NameOfTable GROUP BY
DATENAME(ww,salesDate)

Split a date into two dates

I want to splite two dates into four dates:
Date1:04/01/2012
Date2:12/05/2015
The result that I want is
If datepart(year,date2)=datepart(year,getdate())
Case1
Date1:04/01/2012
Date2:31/12/2014
Date3:01/01/2015
Date4:12/05/2015
Else
Case2
Date1:04/01/2012
Date2:12/05/2015
My question how to obtain date2 and date3 in case1?
You can kind of create them like this:
select '01/01/'+(select cast(datepart(yy,getdate()) as varchar))
select '31/12/'+(select cast(datepart(yy,getdate())-1 as varchar))
If I understand you correctly you want to add "fake" records to your select statement if the first date is in a year that is before the current year and the second one is in the current year.
I've taken the liberty to assume you don't want to add 31/12/ if the first date is actually the 31 of December in the last year.
Here is my suggestion:
;With cte as (
SELECT DateValue, ROW_NUMBER() OVER (ORDER BY DateValue) As rn
FROM Tbl
)
-- Get the first date
SELECT DateValue
FROM cte
WHERE rn = 1
UNION ALL
/*
Add the last date of the previous year.
The where clause will enable you to add this to the select result only on your terms
(if the second date is on the current year and the first date is before Dec 31th of the last year)
*/
SELECT CAST(CAST(YEAR(GETDATE())-1 as varchar) + '-12-31' as date)
FROM cte
WHERE rn = 2
AND YEAR(DateValue) = YEAR(GETDATE())
AND CAST(CAST(YEAR(GETDATE())-1 as varchar) + '-12-31' as date) > (SELECT DateValue FROM cte WHERE rn = 1)
UNION ALL
/*
Add the first date of the current year.
Note that the where clause here is only testing that the second date is on the current year,
while the first date is before the current year.
So it will add the Jan 1st of the current year even if the first date is Dec 31th of the last year.
*/
SELECT CAST(CAST(YEAR(GETDATE()) as varchar) + '-01-01' as date)
FROM cte
WHERE rn = 2
AND YEAR(DateValue) = YEAR(GETDATE())
AND YEAR(GETDATE()) > (SELECT YEAR(DateValue) FROM cte WHERE rn = 1)
UNION ALL
-- add the second date
SELECT DateValue
FROM cte WHERE rn = 2
You can see it working on this fiddle.

Resources