Week ends on Saturday and new week starts on Sunday.
I would like to determine date which will be a Saturday and split dates in SQL Server. Example below:
Start_date - 09/11/2018 - Friday
End_date - 12/11/2018 - Monday
Total number of days = 4
I would like split the days and end results as
Start_date - 09/11/2018 - Friday
Date1 - 10/11/2018 - Saturday
Total number of days = 2
Date2 - 11/11/2018 - Sunday
End_date - 12/11/2018 - Monday
Total number of days = 2
Another example ( start_date and end_date if there are more number of Saturdays e.g. )
start-date - 04/05/2017
end_date - 31/05/2017
Then results should be like below :-
Date1 Date2 no. of days.
------------------------------------
04/05/2017 06/05/2017 3
07/05/2017 13/05/2017 7
14/05/2017 20/05/2017 7
21/05/2017 27/05/2017 7
28/05/2017 31/05/2017 4
Please help.
Thanks & Regards,
VG
If I am not mistaken you are looking for something like this:
DECLARE #StartDate DATE = '2017-05-04'
DECLARE #EndDate DATE = '2017-05-31'
DECLARE #OutputTABLE AS TABLE
(
StartDate DATE NOT NULL,
EndDate DATE NOT NULL
)
DECLARE #NumberOfWeeks INT = DATEDIFF(week, #StartDate, #EndDate)
DECLARE #Counter INT = 0
DECLARE #TempDate DATE = DATEADD(week, #Counter, #StartDate)
WHILE #NumberOfWeeks >= 0
BEGIN
IF #NumberOfWeeks = 0
BEGIN
INSERT INTO #OutputTABLE VALUES (#TempDate, #EndDate);
END
ELSE
BEGIN
INSERT INTO #OutputTABLE VALUES (#TempDate, DATEADD(DAY, -1, DATEADD(week, DATEDIFF(week ,0 , #TempDate) + 1, -1)));
END
SET #TempDate = DATEADD(week, #Counter + 1, DATEADD(day, -1, DATEADD(week, DATEDIFF(week, 0, #StartDate), 0)))
SET #NumberOfWeeks = #NumberOfWeeks - 1
SET #Counter = #Counter + 1
END
SELECT StartDate,
EndDate,
DATEDIFF(day, StartDate, EndDate) + 1 AS NumberOfDays
FROM #OutputTABLE
Here is one way. I couldn't figure out a way with a recursive CTE since you can't aggregate in the recursive part of a recursive CTE.
DECLARE #MinDate DATE = '20170504',
#MaxDate DATE = '20170531'
DECLARE #StartDate datetime, #EndDate datetime
--DATE TABLE... ONE ROW FOR EVERY DAY IN RANGE
IF OBJECT_ID('tempdb..#DateTable') IS NOT NULL DROP TABLE #DateTable
SELECT TOP (DATEDIFF(DAY, #MinDate, #MaxDate) + 1)
Dates = DATEADD(DAY, ROW_NUMBER() OVER(ORDER BY a.object_id) - 1, #MinDate)
INTO #DateTable
FROM sys.all_objects a
CROSS JOIN sys.all_objects b
IF OBJECT_ID('tempdb..#Results') IS NOT NULL DROP TABLE #Results
CREATE TABLE #Results (Date1 DATETIME, Date2 DATETIME, NumOfDays INT)
--INSERT FIRST ROW IN CASE IT STARTS ON A DAY OTHER THAN SUNDAY
INSERT INTO #Results
SELECT
MIN(Dates) as Date1
,MIN(CASE WHEN DATEPART(WEEKDAY,Dates) = 7 THEN Dates END) as Date2
,DATEDIFF(DAY,MIN(Dates),MIN(CASE WHEN DATEPART(WEEKDAY,Dates) = 7 THEN Dates END)) + 1 as NoOfDays
FROM #DateTable
SET #StartDate = (SELECT MIN(CASE WHEN DATEPART(WEEKDAY,Dates) = 1 THEN Dates END) FROM #DateTable)
SET #EndDate = (SELECT MAX(CASE WHEN DATEPART(WEEKDAY,Dates) = 1 THEN Dates END) FROM #DateTable)
--INSERT ALL FULL WEEKS
WHILE #StartDate < #EndDate
BEGIN
INSERT INTO #Results
SELECT
MIN(Dates) as Date1
,MIN(CASE WHEN DATEPART(WEEKDAY,Dates) = 7 THEN Dates END) as Date2
,DATEDIFF(DAY,MIN(Dates),MIN(CASE WHEN DATEPART(WEEKDAY,Dates) = 7 THEN Dates END)) + 1 as NoOfDays
FROM #DateTable
WHERE Dates >= #StartDate
SET #StartDate = DATEADD(DAY,7,#StartDate)
END
--INSERT LAST ROW IF IT ISN'T A FULL WEEK
IF (SELECT MAX(Date2) FROM #Results) <> #MaxDate
BEGIN
INSERT INTO #Results
SELECT
MIN(Dates) as Date1
,MAX(Dates) as Date2
,DATEDIFF(DAY,MIN(Dates),MAX(Dates)) + 1 as NoOfDays
FROM #DateTable
WHERE Dates > (SELECT MAX(Date2) FROM #Results)
END
SELECT * FROM #Results
DROP TABLE #Results
DROP TABLE #DateTable
RETURNS
+-------------------------+-------------------------+-----------+
| Date1 | Date2 | NumOfDays |
+-------------------------+-------------------------+-----------+
| 2017-05-04 00:00:00.000 | 2017-05-06 00:00:00.000 | 3 |
| 2017-05-07 00:00:00.000 | 2017-05-13 00:00:00.000 | 7 |
| 2017-05-14 00:00:00.000 | 2017-05-20 00:00:00.000 | 7 |
| 2017-05-21 00:00:00.000 | 2017-05-27 00:00:00.000 | 7 |
| 2017-05-28 00:00:00.000 | 2017-05-31 00:00:00.000 | 4 |
+-------------------------+-------------------------+-----------+
This will compute your Date2 from your Date1
print dateadd(day,-1,dateadd(wk,datepart(wk,'4/5/2017'),'1/1/2017'))
Related
I have following 2019 data.
Date Calendar_year Weekend_indicator
2019-01-01 2019 weekday
2019-01-01 2019 weekday
2019-01-02 2019 weekday
2019-01-02 2019 weekday
and so on.
I need to give one record a day and another a night value and have it repeated for the entire year's data so that it would look like this.
Date Calendar_year Weekend_indicator day_night
2019-01-01 2019 weekday Day
2019-01-01 2019 weekday Night
2019-01-02 2019 weekday Day
2019-01-02 2019 weekday Night
Here is my code.
DECLARE #Year AS INT,
#FirstDateOfYear DATETIME,
#LastDateOfYear DATETIME
-- You can change #year to any year you desire
SELECT #year = 2019
SELECT #FirstDateOfYear = DATEADD(yyyy, #Year - 1900, 0)
SELECT #LastDateOfYear = DATEADD(yyyy, #Year - 1900 + 1, 0)
-- Creating Query to Prepare Year Data;
WITH cte AS (
SELECT 1 AS DayID,
#FirstDateOfYear AS FromDate,
DATENAME(dw, #FirstDateOfYear) AS Dayname
UNION ALL
SELECT cte.DayID + 1 AS DayID,
DATEADD(d, 1 ,cte.FromDate),
DATENAME(dw, DATEADD(d, 1 ,cte.FromDate)) AS Dayname
FROM cte
WHERE DATEADD(d,1,cte.FromDate) < #LastDateOfYear
)
SELECT c.FromDate AS Date
,#Year as calendar_year
,CHOOSE(datepart(dw, c.FromDate), 'WEEKEND', 'WEEKDAY', 'WEEKDAY',
'WEEKDAY', 'WEEKDAY', 'WEEKDAY', 'WEEKEND') as weekend_indicator
FROM CTE c
CROSS JOIN ( values (1), (2) ) tb (FromDate)
WHERE DayName IN ('Saturday','Sunday')
or dayname not in ('Saturday', 'Sunday')
order by c.FromDate
OPTION (MaxRecursion 1000)
How do I assign the day and the night value and have it repeated?
This simple query might point you in the right direction:
USE TEMPDB
CREATE TABLE #T (DateCol DATE, Calender_Year INT)
INSERT INTO #T VALUES ('20180101', 2018 )
SELECT *
FROM #T
CROSS APPLY (VALUES ('Day'), ('Night') ) AS C (Val)
If you want just to change your code without rewriting it,
add one more row as below:
DECLARE #Year AS INT,
#FirstDateOfYear DATETIME,
#LastDateOfYear DATETIME
-- You can change #year to any year you desire
SELECT #year = 2019
SELECT #FirstDateOfYear = DATEADD(yyyy, #Year - 1900, 0)
SELECT #LastDateOfYear = DATEADD(yyyy, #Year - 1900 + 1, 0);
-- Creating Query to Prepare Year Data;
WITH cte AS (
SELECT 1 AS DayID,
#FirstDateOfYear AS FromDate,
DATENAME(dw, #FirstDateOfYear) AS Dayname
UNION ALL
SELECT cte.DayID + 1 AS DayID,
DATEADD(d, 1 ,cte.FromDate),
DATENAME(dw, DATEADD(d, 1 ,cte.FromDate)) AS Dayname
FROM cte
WHERE DATEADD(d,1,cte.FromDate) < #LastDateOfYear
)
SELECT c.FromDate AS Date
,#Year as calendar_year
,CHOOSE(datepart(dw, c.FromDate), 'WEEKEND', 'WEEKDAY', 'WEEKDAY',
'WEEKDAY', 'WEEKDAY', 'WEEKDAY', 'WEEKEND') as weekend_indicator,
case tb.FromDate when 1 then 'Day' else 'Night' end as day_night -----<<<<<<-----
FROM CTE c
CROSS JOIN ( values (1), (2) ) tb (FromDate)
WHERE DayName IN ('Saturday','Sunday')
or dayname not in ('Saturday', 'Sunday')
order by c.FromDate
OPTION (MaxRecursion 1000)
I use a table variable for create this solution.
DECLARE
#Year int
,#FirstDateOfYear date
,#LastDateOfYear date
,#date_loop date
SET #YEAR = 2019
SELECT
#FirstDateOfYear = DATEADD(yyyy, #Year - 1900, 0)
,#LastDateOfYear = DATEADD(yyyy, #Year - 1900 + 1, 0)
,#date_loop = DATEADD(yyyy, #Year - 1900, 0) --initialize variable for loop
DECLARE #date_table TABLE ([Date] date, [Calendar_year] int, [Weekend_indicator] varchar(10), [day_night] varchar(5))
WHILE #date_loop < #LastDateOfYear
BEGIN
INSERT #date_table
SELECT d.[Date], d.[Calendar_year], d.[Weekend_indicator], ca.[day_night]
FROM (
SELECT
#date_loop AS [Date]
,YEAR(#date_loop) AS [Calendar_year]
,CHOOSE(datepart(dw, #date_loop), 'weekend', 'weekday', 'weekday','weekday', 'weekday', 'weekday', 'weekend') AS [Weekend_indicator]) AS d
CROSS APPLY (
SELECT 'Day' AS [day_night]
UNION
SELECT 'Night'
) AS ca
SET #date_loop = DATEADD(day,1,#date_loop)
END
SELECT *
FROM #date_table
If you don't have a calendar or numbers table, you can use an ad-hoc table
Example
Declare #Date1 date = '2019-01-01'
Declare #Date2 date = '2019-12-31'
Select [Date] = d
,Calendar_year = datepart(YEAR,d)
,Weekend_indicator = case when datename(WEEKDAY,d) in ('Saturday','Sunday') then 'weekend' else 'weekday' end
,day_night
From (
Select Top (DateDiff(DAY,#Date1,#Date2)+1) D=DateAdd(DAY,-1+Row_Number() Over (Order By (Select Null)),#Date1)
From master..spt_values n1,master..spt_values n2
) A
Cross Join (values ('Day'),('Night') ) b(day_night)
Order by D,day_night
Returns
Date Calendar_year Weekend_indicator day_night
2019-01-01 2019 weekday Day
2019-01-01 2019 weekday Night
2019-01-02 2019 weekday Day
2019-01-02 2019 weekday Night
...
2019-12-30 2019 weekday Day
2019-12-30 2019 weekday Night
2019-12-31 2019 weekday Day
2019-12-31 2019 weekday Night
Revised answer: I see an unused (VALUES ...) clause which could be used like so:
CROSS JOIN (VALUES ('Day'), ('Night') ) whatever(day_night)
DB Fiddle
I have the following query that I simplified. Simply it displays a list of counts of records in the last 4 weeks.
SELECT COUNT(*) AS [Counts], Week=1
FROM TableA
WHERE Date >= DATEADD(week,-1,GETDATE())
AND Date <= GETDATE()
UNION
SELECT COUNT(*), 2
FROM TableA
WHERE Date >= DATEADD(week,-2,GETDATE())
AND Date <= DATEADD(week,-1,GETDATE())
UNION
SELECT COUNT(*), 3
FROM TableA
WHERE Date >= DATEADD(week,-3,GETDATE())
AND Date <= DATEADD(week,-2,GETDATE())
UNION
SELECT COUNT(*), 4
FROM TableA
WHERE Date >= DATEADD(week,-4,GETDATE())
AND Date <= DATEADD(week,-3,GETDATE())
Returns:
----------------
| Count | Week |
----------------
| 20 | 1 |
----------------
| 10 | 2 |
----------------
| 30 | 3 |
----------------
| 25 | 4 |
----------------
Suppose I want to modify the query so it returns the last 10 or 20 weeks.
How can I shorten the query so it loops through weeks?
e.g.
declare #w int;
set #w = 10;
while #w <> 0
begin
...;
--how can I do union joins?
set #w = #w - 1;
end
You could avoid UNION and specifying each week by hand by using GROUP BY:
SELECT datepart(week, Date) AS WeekNum, COUNT(*) AS counts
FROM TableA
WHERE Date >= DATEADD(week,-20,GETDATE()) -- num of weeks
GROUP BY datepart(week, Date); -- week of the year
If you need nums from 1 to n then:
WITH cte AS (
SELECT datepart(year, Date) AS [year],
datepart(week, Date) AS WeekNum,
COUNT(*) AS counts
FROM TableA
WHERE Date >= DATEADD(week,-20,GETDATE()) -- num of weeks
GROUP BY datepart(year, Date), datepart(week, Date)
)
SELECT ROW_NUMBER() OVER(ORDER BY [year] DESC, WeekNum DESC) AS WeekNum, counts
FROM cte;
EDIT:
"yes, like if today is wednesday, 20 week will give you a week starting in wednesday"
It could be handled by:
WHERE Date >= DATEADD(week,-20,GETDATE())
=>
WHERE Date >= DATEADD(week,-20,
CAST(DATEADD(DAY, 1-DATEPART(WEEKDAY, GETDATE()), GETDATE()) AS DATE))
I have a requirement to create a Financial year Calendar with
start date = 2019-03-31 and end_date = 2020-03-28
declare #startdate date = '2019-03-30'
declare #enddate date = '2020-03-28'
declare #dates table (date date, MonthNo int)
while #startdate < #enddate
BEGIN
set #startdate = dateadd(dd,1,#startdate)
insert #dates (date)
select #startdate
END
select * from #dates
I will need to populate month number column
MonthNumber : In this case, It can not be obtained through typical query using
DATEPART(MONTH, [date])
Requirement : Month number should be starting at 1 and should be assigned as shown below
NoOfDays trading_month
28 1
28 2
35 3
28 4
28 5
35 6
28 7
28 8
35 9
28 10
28 11
35 12
Ex: Trading month = 1 is between 2019-03-31 and 2019-04-28 and next 28 days = month 2 and next 35 days month = 3 etc..
ps: I do not want to use case statement 12 times to populate month number, is there any alternate way to achieve this
can achieve this way
select *, case when ROW_NUMBER() over (order by date) between 1 and 28 then 1
when ROW_NUMBER() over (order by date) between 29 and 28+28 then 2
when ROW_NUMBER() over (order by date) between 28+28+1 and 28+29+35 then 3
----so on
end MonthNo
from #dates
Here is one option.
Example
Declare #Date1 date = '2019-03-31'
Select [Date]=DateAdd(DAY,Row_Number() over (Order by M,D)-1,#Date1)
,[Year]=DatePart(YEAR,#Date1)
,[Month]=M
From (
Select *
From (Select Top (28) D=Row_Number() Over (Order By (Select Null)) From master..spt_values n1 ) A
Cross Join (Values (1),(2),(4),(5),(7),(8),(10),(11)) B(M)
Union All
Select *
From ( Select Top (35) D=Row_Number() Over (Order By (Select Null)) From master..spt_values n1 ) A
Cross Join (Values (3),(6),(9),(12)) B(M)
) A
Order by 1,2
Returns
Date Year Month
2019-03-31 2019 1
2019-04-01 2019 1
2019-04-02 2019 1
2019-04-03 2019 1
2019-04-04 2019 1
2019-04-05 2019 1
2019-04-06 2019 1
2019-04-07 2019 1
2019-04-08 2019 1
2019-04-09 2019 1
...
2020-03-21 2019 12
2020-03-22 2019 12
2020-03-23 2019 12
2020-03-24 2019 12
2020-03-25 2019 12
2020-03-26 2019 12
2020-03-27 2019 12
2020-03-28 2019 12
Lucky you ... Download and execute the code in my article SQL Server Calendar Table, then download and modify the code in SQL Server Calendar Table: Fiscal Years to fit your definition of a fiscal year and execute that.
I once had a client that ran on 'Crop year' where their fiscal years started the last week of May, and the only way to pull that off was to create a wompload of T-SQL to populate a Calendar table. Once that was done for any given dataset all I had to do was JOIN on the date column and then I could get all the fiscal-related column values I wanted without having to recalculate them every time.
{edit: Here's the relevant code that creates the 4-4-5 from the above Fiscal Weeks article}
USE calendar
GO
/*
Calendar table: Populate the six fiscal_ columns
2015-09-16
*/
Declare #dtYearStart date, #dtStart date, #dtEnd date, #dt date
Declare #fiscal_month tinyint = 1, #fiscal_year smallint , #fiscal_week_in_month tinyint, #fiscal_week_in_year tinyint, #fiscal_day_in_week tinyint, #fiscal_day_in_month tinyint
Declare #counter int = 1, #counter_year int = 1, #counter_month int = 1, #counter_week int = 1, #counter_day int = 1
-- Run this for 19 years from May 2000 to May 2020
WHILE #counter_year <= 19
begin
-- Per the article image, the last day of the year is the last Sunday in May.
SELECT #dtYearStart = MAX(PKDate), #dtEnd = MAX(PKDate)
FROM days
WHERE continuous_year = #counter_year AND calendar_month = 5 AND calendar_day_in_week = 1
-- YEARS and MONTHS
-- Set the year
SELECT #fiscal_year = YEAR(#dtYearStart) + 1, #fiscal_month = 1
SET #counter = 1
WHILE #counter <= 12
begin
SELECT #dtStart = DATEADD(day, 1, #dtEnd)
SELECT #dtEnd = DATEADD(day, CASE WHEN #fiscal_month IN (1, 4, 7, 10) THEN 34 ELSE 27 END, #dtStart)
UPDATE days
SET fiscal_year = #fiscal_year, fiscal_month = #fiscal_month
FROM days
WHERE PKDate >= #dtStart AND PKDate <= #dtEnd
;WITH ro AS (SELECT PKDate, RANK() OVER (ORDER BY PKDate) as row_order FROM days WHERE fiscal_year = #fiscal_year AND fiscal_month = #fiscal_month)
UPDATE days
SET fiscal_day_in_month = row_order
FROM days
JOIN ro ON days.PKDate = ro.PKDate
-- TESTING ONLY, comment the below line out in production
-- SELECT 'Year and Month' as label, PKDate, fiscal_year, fiscal_month, fiscal_day_in_month FROM days WHERE PKDate >= #dtStart AND PKDate <= #dtEnd
SELECT #counter = #counter + 1, #fiscal_month = #fiscal_month + 1
end
-- WEEKS
SELECT #counter = 1, #counter_week = 1, #dtEnd = #dtYearStart
WHILE #counter <= 52
begin
SELECT #dtStart = DATEADD(day, 1, #dtEnd)
SELECT #dtEnd = DATEADD(day, 6, #dtStart)
UPDATE days
SET fiscal_week_in_month = #counter_week, fiscal_week_in_year = #counter
FROM days
WHERE PKDate >= #dtStart AND PKDate <= #dtEnd
-- TESTING ONLY, comment the below line out in production
-- SELECT 'Week' as label, PKDate, fiscal_week_in_year, fiscal_week_in_month FROM days WHERE PKDate >= #dtStart AND PKDate <= #dtEnd
SELECT #counter = #counter + 1
-- Get the fiscal month of the row to determine if the month has 4 or 5 weeks.
SELECT #fiscal_month = fiscal_month FROM days WHERE PKDate = #dtStart
SELECT #counter_week = CASE
WHEN #fiscal_month IN (1, 4, 7, 10) AND #counter_week = 5 THEN 1
WHEN #fiscal_month IN (1, 4, 7, 10) AND #counter_week < 5 THEN #counter_week + 1
WHEN #fiscal_month NOT IN (1, 4, 7, 10) AND #counter_week = 4 THEN 1
WHEN #fiscal_month NOT IN (1, 4, 7, 10) AND #counter_week < 4 THEN #counter_week + 1 END
end
-- DAYS
;WITH ro AS (SELECT PKDate, RANK() OVER (ORDER BY PKDate) as row_order FROM days WHERE fiscal_year = #fiscal_year)
UPDATE days
SET fiscal_day_in_year = row_order
FROM days
JOIN ro ON days.PKDate = ro.PKDate
SELECT #counter_year = #counter_year + 1
end
Good luck.
Jim
I was able to get the expected results with the following query. The only addition to the original table was an identity column. Using most of your original code:
declare #startdate date = '2019-03-30'
declare #enddate date = '2020-03-28'
declare #dates table (pkindex int IDENTITY(1,1), [date] date, MonthNo tinyint)
while #startdate < #enddate
BEGIN
set #startdate = dateadd(dd,1,#startdate)
insert #dates ([date])
select #startdate
END
DECLARE #requirments TABLE (NoOfDays tinyint, trading_month tinyint)
INSERT INTO #requirments VALUES
(28, 1), (28, 2), (35, 3), (28, 4), (28, 5), (35, 6), (28, 7), (28, 8), (35, 9)
,(28, 10), (28, 11), (35, 12)
UPDATE #dates
SET MonthNo =
(SELECT MIN(R.trading_month)
FROM #requirments R
WHERE pkindex <
(SELECT SUM(R2.NoOfDays)
FROM #requirments R2
WHERE R2.trading_month < R.trading_month + 1
) + 1
)
SELECT * FROM #dates
Not sure if I understand your goal here exactly, why 1 = 28 specifically. However it seems like your datepart idea was inline with your desired solution if you just do this I get the layout you wanted.
declare #startdate date = '2019-03-30'
declare #enddate date = '2020-03-28'
declare #dates table (NoOfDays date, trading_mo int)
while #startdate < #enddate
BEGIN
set #startdate = dateadd(dd,1,#startdate)
insert #dates (NoOfDays)
select #startdate
END
select count(NoOfDays) noOfDays,
datepart(month,NoOfDays) trading_mo
from #dates
group by datepart(month,NoOfDays)
order by trading_mo
If the day component of today is less than or equal to 19, I need records from the 20th of previous month, into the future. For example:
dbo.Invoices
Date InvoiceNumber
10/20/2012 x
11/13/2012 y
11/20/2012 z
12/19/2012 aa
12/21/2012 bb
Today (11/13), I need x, y, z, aa, bb.
On 11/20, I need z, aa, bb.
On 12/19, I need z, aa, bb.
On 12/21, I need bb.
This is what I have so far:
SELECT [omitted]
,CASE
WHEN DAY(GETDATE()) <= 19 THEN
FROM QB_INVOICES_HEADER a
INNER JOIN CI_INVOICEADJS b
ON a.InvoiceNumber = b.InvoiceNumber
WHERE DATEDIFF(day, a.InvoiceDt, b.EffectiveCheckingDt) <= 60
ORDER BY b.EffectiveCheckingDt ASC
the code below solves your task. I used table variable #invoices instead of your dbo.invoices table
DECLARE #invoices TABLE ([date] DATE, invoiceNumber varchar(255));
INSERT INTO #invoices VALUES
('10/20/2012', 'x'),
('11/13/2012', 'y'),
('11/20/2012', 'z'),
('12/19/2012', 'aa'),
('12/21/2012', 'bb');
DECLARE #StartDate DATE;
DECLARE #today DATE ;
SET #today = '11/13/2012';
--SET #today = '11/20/2012';
--SET #today = '12/19/2012';
--SET #today = '12/21/2012';
IF DAY(#today) <= 19 BEGIN
SET #startDate = DATETIMEFROMPARTS(YEAR(#today), MONTH(#today) - 1, 20,0,0,0.0,0);
END
ELSE BEGIN
SET #startDate = #today
END
SELECT [date], invoiceNumber
FROM #invoices
WHERE [date] >= #StartDate
You need to use DATEPART(DAY, [YOUR DATE COLUMN]) to tell what day of the month it is.
Just SQL Query :
SQLFIDDLEExample
SELECT
InvoiceNumber
FROM Invoices
WHERE Date >= CASE WHEN DAY(GETDATE())<=19
THEN CAST(MONTH(DATEADD (mm , -1 , GETDATE() )) as varchar(2))+
'/20/'+CAST(YEAR(DATEADD (mm , -1 , GETDATE() )) as varchar(4))
ELSE CONVERT(VARCHAR(10), GETDATE(), 101)
END
If you want differrent date just replace GETDATE() to '10/19/2012'
SELECT
InvoiceNumber
FROM Invoices
WHERE Date >= CASE WHEN DAY('12/19/2012')<=19
THEN CAST(MONTH(DATEADD (mm , -1 , '12/19/2012' )) as varchar(2))+
'/20/'+CAST(YEAR(DATEADD (mm , -1 , '12/19/2012' )) as varchar(4))
ELSE CONVERT(VARCHAR(10), '12/19/2012', 101)
END
Result with second query :
| INVOICENUMBER |
-----------------
| z |
| aa |
| bb |
I have a table with start and end dates in. My goal is to have a table that has grouped these dates into how many days the period spans. I thought I had the solution with a simple SQL statement (MS SQL Server 2005) but I want to exclude weekends.
SELECT DATEDIFF(D, StartDate, EndDate)+1 AS Days,
COUNT(ID) as Count
FROM myDateTable
GROUP BY DATEDIFF(D, StartDate, EndDate)
This gives a record set of:
Days Count
1 4
2 2
4 1
7 2
Is this possible to exclude the weekends in the SQL statement and if not can it be done using ASP and a array perhaps?
Well then, using Sql Server 2005, you can try something like
DECLARE #Table TABLE(
ID INT,
StartDate DATETIME,
EndDate DATETIME
)
INSERT INTO #Table (ID,StartDate,EndDate) SELECT 1, '25 Jan 2009', '31 Jan 2009'
INSERT INTO #Table (ID,StartDate,EndDate) SELECT 2, '01 Jan 2009', '07 Jan 2009'
INSERT INTO #Table (ID,StartDate,EndDate) SELECT 3, '01 Jan 2009', '14 Jan 2009'
DECLARE #MinDate DATETIME,
#MaxDate DATETIME
SELECT #MinDate = MIN(StartDate) ,
#MaxDate = MAX(EndDate)
FROM #Table
--Create a temp result set between the Min and Max dates, with all dates, and their weekday names
;WITH DayValues AS(
SELECT #MinDate DateVal,
DATENAME(dw, #MinDate) DateValName
UNION ALL
SELECT DateVal + 1,
DATENAME(dw, DateVal + 1) DateValName
FROM DayValues
WHERE DateVal + 1 <= #MaxDate
),
--select the count of days for each StartDate and EndDate pair, excluding Saturdays and Sundays
DateCounts AS(
SELECT ID,
(
SELECT COUNT(1)
FROM DayValues
WHERE DateVal BETWEEN StartDate AND EndDate
AND DateValName NOT IN ('Saturday', 'Sunday')
) DateCount
FROM #Table
)
--Now group and count
SELECT DateCount,
COUNT(ID) TotalCount
FROM DateCounts
GROUP BY DateCount
OPTION (MAXRECURSION 0)
Output
DateCount TotalCount
----------- -----------
5 2
10 1
EDIT: Brief Explenation
You need to determine the number of days between (and including) 2 dates, that are not weekends.
So using a CTE, I create a temporary result set of dates ebwteen the Min and Max dates, and their Weekday Name (eg Monday, Tuesday... Sunday).
Then, for each of your date pairs, I count the number of entries that does not correspond to Saturday and Sunday.
Here's an ASP function that counts days weekdays between two dates.
<%
Dim StartDate, EndDate
StartDate = CDate("1/1/2010")
EndDate = CDate("2/1/2010")
Response.Write(WeekDayCount(StartDate, EndDate))
Function WeekDayCount(StartDate, EndDate)
dim tempDate, dayCount
tempDate = StartDate
dayCount = 0
'Step forward one day, counting non-week days
While tempDate <> EndDate
'The 1 and 7 might need to be tweaked depending on the locale of your
'server. 1 = Sunday, 7 = Saturday
If DatePart("w", tempDate) <> 1 And DatePart("w", tempDate) <> 7 Then
dayCount = dayCount + 1
End If
tempDate = DateAdd("d", 1, tempDate)
Wend
WeekDayCount = dayCount
End Function
%>
Have a look at ##DATEFIRST,
and look a this;
SELECT DATEPART(DW,GETDATE()).
You should be able to run a query WHERE the 'DW' is not equal to the weekend numbers.