Need SQL Server Query help, Newbie - sql

I have a table that has the following columns.
id,
compid(used to identify a piece of equipment),
startalarmdate,
endalarmdate
when a piece of equipment goes into alarm, I insert the compid and startalarmdate(with the current time) into the table and when the equipment comes out of alarm I fill in the null in that same row in the endalarmdate column with the current time.
so I end up with something like this in the table
417,6,Sun Oct 30 18:48:17 CDT 2011,Mon Oct 31 09:49:21 CDT 2011
422,6,Mon Oct 31 10:19:19 CDT 2011,Mon Oct 31 12:19:22 CDT 2011
427,6,Mon Oct 31 20:19:56 CDT 2011,Tue Nov 01 09:50:59 CDT 2011
429,6,Tue Nov 01 21:51:41 CDT 2011,Wed Nov 02 09:52:37 CDT 2011
432,6,Wed Nov 02 21:23:23 CDT 2011,Fri Nov 04 16:26:29 CDT 2011
I was able to build a query that gives me a total downtime in hours for each event, but what I would like to do now is build a query that gives me a total hours in downtime for each day of a month. Id like it to have the compid all the way to the left, then have each day of the month to the right of the compid in a column on the same row. Id like the days with no downtime to be null. Is it possible to do that with the way this table is setup?

Step 1: set up a temp table containing the desired "time blocks" that you want to total for. These blocks could be for any range of time; in your example, it would be one entry for ever day (24-hour period) in the month.
CREATE TABLE #TimeRanges
(
RangeStart datetime not null
,RangeEnd datetime not null
)
Left-outer-joining this table on your data ensures you get at least one row per time block (day), even if there were no alarms occuring that day:
SELECT
tr.RangeStart -- Use start of each time block to identify the block
,md.CompId -- With left outer join, will be 0 or more rows for each block
,sum(datediff(hh
,case
when tr.RangeStart > md.StartAlarmDate then tr.RangeStart
else md.StartAlarmDate
end
,case
when tr.RangeEnd > md.EndAlarmDate then tr.RangeEnd
else md.EndAlarmDate
end)) HoursInRange
from #TimeRanges tr
left outer join MyData md
on md.StartAlarmDate < tr.RangeEnd
and md.EndAlarmDate > tr.From
group by
tr.RangeStart
,md.CompId
(I can't test this code, some debugging may be required--but the concept is solid. I'll let you worry about rounding partial hours, and whether you want > and <, or >= and <= (things may get tricky if an alarm starts and/or ends at the exact same point in time as a block boundary).
Edit/Addenda
Here's a fairly basic way to set up the temp table used in the routine (this code, I tested):
-- Set up and initialize some variables
DECLARE
#FirstDay datetime
,#NumberOfDays int
SET #FirstDay = 'Oct 1, 2011' -- Without time, this makes it "midnight the morning of" that day
SET #NumberOfDays = 91 -- Through Dec 31
-- Creates a temporary table that will persist until it is dropped or the connection is closed
CREATE TABLE #TimeRanges
(
RangeStart datetime not null
,RangeEnd datetime not null
)
-- The order in which you add rows to the table is irrelevant. By adding from last to first, I
-- only have to fuss around with one variable, instead of two (the counter and the end-point)
WHILE #NumberOfDays >= 0
BEGIN
INSERT #TimeRanges (RangeStart, RangeEnd)
values ( dateadd(dd, #NumberOfDays, #FirstDay) -- Start of day
,dateadd(dd, #NumberOfDays + 1, #FirstDay)) -- Start of the next day
SET #NumberOfDays = #NumberOfDays - 1
END
-- Review results
SELECT *
from #TimeRanges
order by RangeStart
-- Not necessary, but doesn't hurt, especially when testing code
DROP TABLE #TimeRanges
Note that by making RangeEnd the start of the next day, you have to be careful with your greaterthans and lessthans. The details can get very finicky and fussy there, and you'll want to do a lot of edge-case testing (what if alarm starts, or ends, exactly at Dec 16 2011 00:00.000). I'd go with that, because overall it's simpler to code for than for junk like 'Dec 16, 2011 23:59.997'

As mentionned by #paulbailey, you want to use the DATEDIFF function to get the amount of downtime.
To extract the dates and downtime period (I'm adding a bit more columns that you might need)..
SELECT compid,
YEAR(startalarmdate) AS [Year],
MONTH(startalarmdate) AS [Month],
DAY(startalarmdate) AS [Day],
DATEDIFF(ss, startalarmdate, endalarmdate) AS DowntimeInSeconds --You will need to convert thid later to the format you wish to use
FROM YourTable
/* WHERE CLAUSE - Most probably a date range */
Now this gives you the downtime in seconds for each days that had a downtime.
To get the amount of downtime per day is easy as grouping by day and SUMing up the downtimes (again adding more columns that you might need)..
SELECT compid,
[Year],
[Month],
[Day],
SUM(DowntimeInSeconds) AS TotalDowntimeInSeconds
FROM (SELECT compid,
YEAR(startalarmdate) AS [Year],
MONTH(startalarmdate) AS [Month],
DAY(startalarmdate) AS [Day],
DATEDIFF(ss, startalarmdate, endalarmdate) AS DowntimeInSeconds --You will need to convert thid later to the format you wish to use
FROM YourTable
/* WHERE CLAUSE - Most probably a date range */) AS GetDowntimes
GROUP BY compid, [Year], [Month], [Day]
ORDER BY [Year], [Month], [Day], compid
And I believe this should help you get where you want to.
Edit:
To have the days that have no downtime included in this result, you need to first have a list of ALL days present in a month. You take this list and you LEFT OUTER JOIN the result from the above query (you will have to remove the ORDER BY first).

The case statement in Philip Kelley's answer does not work, although the main principal of filling a temp table with dates and left joining stands true. For my version I've used the same variable to start - an input date and the number of days to report on.
DECLARE #StartDate DATETIME, #Days INT
SELECT #StartDate = GETDATE(),
#Days = 5
-- REMOVE ANY TIME FROM THE STARTDATE
SET #StartDate = DATEADD(DAY, 0, DATEDIFF(DAY, 0, #StartDate))
-- CREATE THE TEMP TABLE OF DATES USING THE SAME METHODOLOGY
DECLARE #Dates TABLE (AlarmDate SMALLDATETIME NOT NULL PRIMARY KEY)
WHILE (#Days > 0)
BEGIN
INSERT #Dates VALUES (DATEADD(DAY, #Days, #StartDate))
SET #Days = #Days - 1
END
-- NOW SELECT THE DATA
SELECT AlarmDate,
CompID,
CONVERT(DECIMAL(10, 2), ISNULL(SUM(DownTime), 0) / 3600.0) [DownTime]
FROM #Dates
LEFT JOIN
( SELECT DATEADD(DAY, 0, DATEDIFF(DAY, 0, StartAlarmDate)) [StartAlarmDate],
CompID,
DATEDIFF(SECOND, StartAlarmDate, CASE WHEN EndAlarmDate >= DATEADD(DAY, 1, DATEDIFF(DAY, 0, StartAlarmDate)) THEN DATEADD(DAY, 1, DATEDIFF(DAY, 0, StartAlarmDate)) ELSE EndAlarmDate END) [DownTime]
FROM [yourTable]
UNION ALL
SELECT DATEADD(DAY, 0, DATEDIFF(DAY, 0, EndAlarmDate)) [Date],
CompID,
DATEDIFF(SECOND, DATEADD(DAY, 1, DATEDIFF(DAY, 0, StartAlarmDate)), EndAlarmDate) [DownTime]
FROM [yourTable]
WHERE EndAlarmDate >= DATEADD(DAY, 1, DATEDIFF(DAY, 0, StartAlarmDate))
) data
ON StartAlarmDate = AlarmDate
GROUP BY AlarmDate, CompID
I have used seconds for the date diff and divided by 3600.0 after the seconds have been summed up as 60 rows each with a difference of a minute would sum to 0 when using hours for a datediff.

Related

nth day to nth month in SQL Server

I need to get date between two date range. That is nth day of nth month.
For example, I need to know 23rd day of every 2nd month between January 1, 2015 to December 30, 2015.
I need the query in T-SQL for SQL Server
You should use recursive query in MSSQL.
Here the first WITH DT is a table where you set up conditions:
WITH DT AS
(
SELECT CAST('January 1, 2015' as datetime) as dStart,
CAST('December 30, 2015' as datetime) as dFinish,
31 as nDay,
2 as nMonth
),
T AS
(
SELECT DATEADD(DAY,nDay-1,
DATEADD(MONTH, DATEDIFF(MONTH, 0, DStart), 0)
) as d,0 as MonthNumber
FROM DT
UNION ALL
SELECT DATEADD(DAY,nDay-1,
DATEADD(MONTH, DATEDIFF(MONTH, 0, DStart)
+T.MonthNumber+nMonth,0)
)as d, T.MonthNumber+nMonth as MonthNumber
FROM T,DT
WHERE DATEADD(DAY,nDay-1,
DATEADD(MONTH, DATEDIFF(MONTH, 0, DStart)
+T.MonthNumber+nMonth,0)
)<=DT.dFinish
)
SELECT d FROM T,DT WHERE DAY(d)=DT.nDay
SQLFiddle demo
Is this what you are trying to achieve?
DECLARE #startDate datetime
DECLARE #endDate datetime
DECLARE #monthToFind INT
DECLARE #dayToFind INT
SET #startDate = '01/01/2015'
SET #endDate = '12/31/2015'
SET #monthToFind = 2
SET #dayToFind = 20
IF MONTH(#startDate) + (#monthToFind - 1) BETWEEN MONTH(#startDate) AND MONTH(#endDate)
AND YEAR(#startDate) = YEAR(#endDate)
BEGIN
DECLARE #setTheDate datetime
SET #setTheDate = CAST(MONTH(#startDate) + (#monthToFind - 1) AS varchar) + '/' + CAST(#dayToFind AS varchar) + '/' + CAST(YEAR(#startDate) AS varchar)
SELECT DATENAME(DW,#setTheDate)
END
This is clearly homework, and the point of homework is to learn how things work and to solve problems, not to get others to do it for you. So - pointers for doing this properly, rather than an answer to copy and paste.
Numbers / tally tables are ideal for this sort of thing. Create a function that returns a list of sequential integers in a range. More general than a calendar table, and you can use it to derive a calendar table later if you need one.
When you've got that, DATEDIFF will give you the number of days between two dates. Use that to work out the size of your range, DATEADD to increment your date and possibly DATEPART to check that a date is the nth day of the month.
Mess about with those bits for a little while and you'll work it out.

SQL query to find employee aniversary

I need to find anniversary date and anniversary year of employees and send email in every 14 days.But I have a problem with last week of December when using the following query if start date and end date are in different years.
Select * from Resource
where (DATEPART(dayofyear,JoinDate)
BETWEEN DATEPART(dayofyear,GETDATE())
AND DATEPART(dayofyear,DateAdd(DAY,14,GETDATE())))
Instead of comparing to a dayofyear (which resets to zero at jan 1st and is the reason your query breaks within 14 days of the end of the year) you could update the employee's joindate to be the current year for the purpose of the query and just compare to actual dates
Select * from Resource
-- Add the number of years difference between joinDate and the current year
where DATEADD(year,DATEDIFF(Year,joinDate,GetDate()),JoinDate)
-- compare to range "today"
BETWEEN GetDate()
-- to 14 days from today
AND DATEADD(Day,14,GetDate())
-- duplicate for following year
OR DATEADD(year,DATEDIFF(Year,joinDate,GetDate())+1,JoinDate) -- 2016-1-1
BETWEEN GetDate()
AND DATEADD(Day,14,GetDate())
Test query:
declare #joindate DATETIME='2012-1-1'
declare #today DATETIME = '2015-12-26'
SELECT #joinDate
where DATEADD(year,DATEDIFF(Year,#joinDate,#today),#JoinDate) -- 2015-1-1
BETWEEN #today -- 2015-12-26
AND DATEADD(Day,14,#today) -- 2016-01-09
OR DATEADD(year,DATEDIFF(Year,#joinDate,#today)+1,#JoinDate) -- 2016-1-1
BETWEEN #today -- 2015-12-26
AND DATEADD(Day,14,#today) -- 2016-01-09
(H/T #Damien_The_Unbeliever for a simple fix)
The above correctly selects the joinDate which is in the first week of Jan (note I've had to fudge #today as Ive not managed to invent time travel).
The above solution should also solve the issue with leap years that was hiding in your original solution.
Update
You expressed in comments the requirement to select AnniversaryDate and Years of service, you need to apply some CASE logic to determine whether to add 1 (year or date) to your select
select *,
CASE
WHEN DATEADD(YEAR,DATEDIFF(Year,JoinDate,GETDATE()),JoinDate) < GetDate()
THEN DATEDIFF(Year,JoinDate,GETDATE())+1
ELSE DATEDIFF(Year,JoinDate,GETDATE())
END as [Years],
CASE WHEN DATEADD(YEAR,DATEDIFF(Year,JoinDate,GETDATE()),JoinDate) < GetDate()
THEN DATEADD(YEAR,DATEDIFF(Year,JoinDate,GETDATE())+1,JoinDate)
ELSE DATEADD(YEAR,DATEDIFF(Year,JoinDate,GETDATE()),JoinDate)
end as [AnniversaryDate]
.... // etc
You could do this:
Select * from Resource
where DATEPART(dayofyear,JoinDate)
BETWEEN DATEPART(dayofyear,GETDATE())
AND DATEPART(dayofyear,DateAdd(DAY,14,GETDATE()))
OR
DATEPART(dayofyear,JoinDate)
BETWEEN (DATEPART(dayofyear,GETDATE()) + 365)
AND (DATEPART(dayofyear,DateAdd(DAY,14,GETDATE())) + 365)
Try this:
DECLARE #Today DATE = GETDATE() --'12/25/2013'
DECLARE #Duration INT = 14
;WITH Recur AS
(
SELECT #Today AS RecurDate
UNION ALL
SELECT DATEADD(DAY, 1, RecurDate)
FROM Recur
WHERE DATEDIFF(DAY, #Today, RecurDate)+1 < #Duration
)
SELECT
r.*
FROM
Resource r
JOIN Recur
ON CONVERT(VARCHAR(5), JoinDate, 101) = CONVERT(VARCHAR(5), RecurDate, 101)
WHERE JoinDate < #Today
You can use the SQL DATEADD() function with week number parameter
Here is how you can use it:
DECLARE #date date = getdate()
Select * from Resource
where
JoinDate BETWEEN #date AND DATEADD(ww,2,#date)

TSQL select columns from rollup data columns

I have a rollup data table which stores data for daily counts, monthly counts and yearly counts.
"rollup_type" designates if its a daily(1)/monthly(2)/yearly data(3). For a yearly record, both monthl/daily is null. For monthly record, daily is null.
I am trying to do a simple SELECT based on input start date and end date with no success. Here is what I tried which isn't working correctly.
declare #start_date datetime = '2013-02-01'
declare #enddate datetime = '2014-01-12'
select * from olr_rollup_data rd
where ( rd.Year > DATEPART(YYYY, #start_date) or ( rd.Year = DATEPART(YYYY, #start_date) and ( (rd.Month > DATEPART(MM, #start_date) and rd.day is null) or (rd.MONTH = DATEPART(MM, #start_date) and rd.day >= DATEPART(DD, #start_date) ))))
and ( rd.Year < DATEPART(YYYY, #enddate) or ( rd.Year = DATEPART(YYYY, #enddate) and ( (rd.Month < DATEPART(MM, #enddate) and rd.day is null) or ( rd.MONTH = DATEPART(MM, #enddate) and rd.Day <= DATEPART(DD, #enddate) ))))
Basically, a generic select statement which will use combination of daily, monthly and yearly data from input dates. It should select days plus full month when input dates cover full month in between and so on.
I would appreciate if you help figure out correct select statement. Thank you.
Dates are always a pain to work with, that is why it is nice to use the built in date time functions when available. Sadly that won't work here, we have to figure out some tricks.
One way to work with dates as "numbers" is to multiply the year by 10000, the month by 100 and add these numbers to the day of the month. This will give you an integer where the digits look like this
YYYYMMDD
While disjointed (there are a lot of integers you will never see) any integer with this representation has the same cardinality as the date it represents (those that are larger as a date are also larger as an integer.)
We can use this to solve your problem as follows:
DECLARE #startDate INTEGER = 20130201
DECLARE #endDate INTEGER = 20140112
SELECT *
FROM
(
SELECT ((year*10000)+(ISNULL(month,0)*100)+ISNULL(day,0)) as dateInt, *
FROM olr_rollup_date
) sub
WHERE dateInt >= #startDate AND dateInt <= #endDate
This will include roll up row for the month that are "surrounded". Since we default the null values to 0 a month null for May of 2014 would be 20140500. This is greater than any date in April and less than any date June but smaller than any date in May.
Years will work in a similar way.

How to get a list of Week Start Date (Monday) and End Date (Sunday) between two dates?

I am just finding a way to get a list of Start Week and End Week between two date range.
For e.g. if I call a function or a stored procedure say
GetWeekDates ('21 Mar 2014','21 Mar 2014')
Then I should get a table as:
Start Week | End Week
17 March 2014 | 23 Mar 2014
24 March 2014 | 30 Mar 2014
....
I don't want to use CURSOR or WHILE Loop.
Any direction where I should lead to?
I am just doing a re factor on existing code.
Kind regards,
Am
This will work as long as the intervals are 38 years or less. It will offer better performance and it does not rely on the local setting of the server.
This setting will cause your script to return wrong result:
set datefirst 1
select * from dbo.fnGetWeeksBetweenDates('2014-03-21','2014-03-21')
This means your local setting currently conflicts with your needs and your code is compensating.
Here is the script. The script is limited to 38 years for performance reasons (I find it unlikely that you need bigger intervals than that). It will be fairly easy to extend it to more years.
DECLARE #FromDate DATE = '2014-03-21'
DECLARE #ToDate DATE = '2014-03-24'
SELECT #fromdate = dateadd(day, datediff(day, 0, #FromDate)/7*7, 0),
#todate = dateadd(day, datediff(day, 0, #ToDate)/7*7, 6)
SELECT dateadd(d, number * 7, #fromdate) Start_Week,
dateadd(d, number * 7 + 6, #fromdate) End_Week
FROM
master..spt_values
WHERE type = 'P' and
#todate >= dateadd(d, number * 7, #fromdate)
Result:
Start_Week End_Week
2014-03-17 2014-03-23
2014-03-24 2014-03-30
I end up going through WITH statement and it is much faster than any other way; refactor mission accompliseded
CREATE FUNCTION fnGetWeeksBetweenDates
(
#FromDate DATETIME,
#ToDate DATETIME
) RETURNS #tbl TABLE (StartWeek date, EndWeek date)
AS BEGIN
DECLARE #TOTALWEEK INT
SET #FromDate = DATEADD(DAY,-1*DATEPART(dw,#FromDate)+2,#FromDate)
SET #TOTALWEEK = DATEDIFF(ww,#FromDate,#ToDate)+1;
WITH weekdays (StartWeek, EndWeek) as
(
select top (#TOTALWEEK) StartWeek = DateAdd(Week, ROW_NUMBER()
OVER (ORDER BY object_id)-1, #FromDate),
EndWeek = DateAdd(Week, ROW_NUMBER()
OVER (ORDER BY object_id)-1, #FromDate)
FROM SYS.all_objects
)
insert into #tbl
select StartWeek, DATEADD(day, 6, EndWeek) as EndWeek From weekdays;
RETURN
END;
Here is how you can call:
select * from dbo.fnGetWeeksBetweenDates('21 MAR 2014', '21 MAR 2015')

Calculating in SQL the first working day of a given month

I have to calculate all the invoices which have been paid in the first 'N' days of a month. I have two tables
. INVOICE: it has the invoice information. The only field which does matter is called 'datePayment'
. HOLYDAYS: It is a one column table. Entries at this table are of the form "2009-01-01",
2009-05-01" and so on.
I should consider also Saturdays and Sundays
(this might be not a problem because I could insert those days at the Hollidays table in order to consider them as hollidays if neccesary)
The problem is to calculate which is the 'payment limit'.
select count(*) from invoice
where datePayment < PAYMENTLIMIT
My question is how to calculate this PAYMENTLIMIT. Where PAYMENTLIMIT is 'the fifth working day of every month'.
The query should be run under Mysql and Oracle therefore standard SQL should be used.
Any hint?
EDIT
In order to be consistent with the title of the question the pseudo-query should the read as follows:
select count(*) from invoice
where datePayment < FIRST_WORKING_DAY + N
then the question can be reduced to calculate the FIRST_WORKING_DAY of every month.
You could look for the first date in a month, where the date is not in the holiday table and the date is not a weekend:
select min(datePayment), datepart(mm, datePayment)
from invoices
where datepart(dw, datePayment) not in (1,7) --day of week
and not exists (select holiday from holidays where holiday = datePayment)
group by datepart(mm, datePayment) --monthnr
Something like this might work:
create function dbo.GetFirstWorkdayOfMonth(#Year INT, #Month INT)
returns DATETIME
as begin
declare #firstOfMonth VARCHAR(20)
SET #firstOfMonth = CAST(#Year AS VARCHAR(4)) + '-' + CAST(#Month AS VARCHAR) + '-01'
declare #currDate DATETIME
set #currDate = CAST(#firstOfMonth as DATETIME)
declare #weekday INT
set #weekday = DATEPART(weekday, #currdate)
-- 7 = saturday, 1 = sunday
while #weekday = 1 OR #weekday = 7
begin
set #currDate = DATEADD(DAY, 1, #currDate)
set #weekday = DATEPART(weekday, #currdate)
end
return #currdate
end
I'm not 100% sure about whether the "weekday" numbers are fixed or might depend on your locale on your SQL Server. Check it out!
Marc
Rather than a Holidays table of days to exclude, we use the calendar table approach: one row for every day the application will ever need (thirty years spans a modest 11K rows). So not only does it have an is_weekday column, it has other things relevant to the enterprise e.g. julianized_date. This way, every possible date would have a ready-prepared value for first_working_day_this_month and finding it involves a simple lookup (which SQL products tend to be optimized for!) rather than 'calculating' it each time on the fly.
We have dates table in our application (filled with all dates and date parts for some tens of years), what allows various "missing" date manipulations, like (in pseudo-sql):
select min(ourdates.datevalue)
from ourdates
where ourdates.year=<given year> and ourdates.month=<given month>
and ourdates.isworkday
and not exists (
select * from holidays
where holidays.datevalue=ourdates.datevalue
)
Ok, at a first stab, you could put the following code into a UDF and pass in the Year and Month as variables. It can then return TestDate which is the first working day of the month.
DECLARE #Month INT
DECLARE #Year INT
SELECT #Month = 5
SELECT #Year = 2009
DECLARE #FirstDate DATETIME
SELECT #FirstDate = CONVERT(varchar(4), #Year) + '-' + CONVERT(varchar(2), #Month) + '-' + '01 00:00:00.000'
DROP TABLE #HOLIDAYS
CREATE TABLE #HOLIDAYS (HOLIDAY DateTime)
INSERT INTO #HOLIDAYS VALUES('2009-01-01 00:00:00.000')
INSERT INTO #HOLIDAYS VALUES('2009-05-01 00:00:00.000')
DECLARE #DateFound BIT
SELECT #DateFound = 0
WHILE(#DateFound = 0)
BEGIN
IF(
DATEPART(dw, #FirstDate) = 1
OR
DATEPART(dw, #FirstDate) = 1
OR
EXISTS(SELECT * FROM #HOLIDAYS WHERE HOLIDAY = #FirstDate)
)
BEGIN
SET #FirstDate = DATEADD(dd, 1, #FirstDate)
END
ELSE
BEGIN
SET #DateFound = 1
END
END
SELECT #FirstDate
The things I don`t like with this solution though are, if your holidays table contains all days of the month there will be an infinite loop. (You could check the loop is still looking at the right month) It relies upon the dates being equal, eg all at time 00:00:00. Finally, the way I calculate the 1st of the month past in using string concatenation was a short cut. There are much better ways of finding the actual first day of the month.
Gets the first N working days of each month of year 2009:
select * from invoices as x
where
datePayment between '2009-01-01' and '2009-12-31'
and exists
(
select
1
from invoices
where
-- exclude holidays and sunday saturday...
(
datepart(dw, datePayment) not in (1,7) -- day of week
/*
-- Postgresql and Oracle have programmer-friendly IN clause
and
(datepart(yyyy,datePayment), datepart(mm,datePayment))
not in (select hyear, hday from holidays)
*/
-- this is the MSSQL equivalent of programmer-friendly IN
and
not exists
(
select * from holidays
where
hyear = datepart(yyyy,datePayment)
and hmonth = datepart(mm, datePayment)
)
)
-- ...exclude holidays and sunday saturday
-- get the month of x datePayment
and
(datepart(yyyy, datePayment) = datepart(yyyy, x.datePayment)
and datepart(mm, datePayment) = datepart(mm, x.datePayment))
group by
datepart(yyyy, datePayment), datepart(mm, datePayment)
having
x.datePayment < MIN(datePayment) + #N -- up to N working days
)
Returns the first Monday of the current month
SELECT DATEADD(
WEEK,
DATEDIFF( --x weeks between 1900-01-01 (Monday) and inner result
WEEK,
0, --1900-01-01
DATEADD( --inner result
DAY,
6 - DATEPART(DAY, GETDATE()),
GETDATE()
)
),
0 --1900-01-01 (Monday)
)
SELECT DATEADD(day, DATEDIFF (day, 0, DATEADD (month, DATEDIFF (month, 0, GETDATE()), 0) -1)/7*7 + 7, 0);
select if(weekday('yyyy-mm-01') < 5,'yyyy-mm-01',if(weekday('yyyy-mm-02') < 5,'yyyy-mm-02','yyyy-mm-03'))
Saturdays and Sundays are 5, 6 so you only need two checks to get the first working day