Getting dates between specific dates comma-separated - sql-server-2008

I have the following table:
CREATE TABLE dbo.Test
(
Name NVARCHAR(50)
,StartDate DATE
,EndDate DATE
)
INSERT INTO dbo.Test VALUES('ABC','28-Feb-14','03-Mar-14')
INSERT INTO dbo.Test VALUES('DEF','04-Mar-14','04-Mar-14')
Basically this contain start and end date of leave for a given user. I am expecting an output as shown below.
Expected output:
Name | WorkHour| LeaveHour | Remarks
-------------------------------------
ABC | 27 | 18 | 28-Feb, 03-Mar
DEF | 36 | 9 | 04-Mar
1 day of leave corresponds to 9 hours and a work week refers to Friday to the next Thursday. In this case that would be from 28-Feb to 06-Mar.
WorkHour refers to number of hours user has worked barring the leaves and not including the weekends.
LeaveHour refers to the number of hours user is on leave.
'Remarks' refers to distinct leaves for the user between StartDate and EndDate values that should appear as comma separated.
I am able to get the work hour (including weekends which is not desired), leave hour values but finding it difficult to have remarks and value excluding weekends
SELECT
RN.Name
,ISNULL(45 - ((DATEDIFF(DD, VT.StartDate, VT.EndDate) + 1) * 9 ), 0) AS 'WorkHours'
,ISNULL(((DATEDIFF(DD, VT.StartDate, VT.EndDate) + 1) * 9 ), 0) AS 'LeaveHours'
--distinct leave dates seperated by comma should be displayed as remarks
FROM
Test VT
LEFT JOIN
ResourceNames RN ON VT.UserId = RN.UserId
Can anyone help?

This should not be done in SQL, but here is a function that will do what you want:
create function CSVDates (#startDate datetime, #endDate datetime)
returns nvarchar(4000)
as
begin
declare #csv nvarchar(4000) = ''
declare #maxDays int = DATEDIFF(DD, #startDate, #endDate)
declare #count int = 0
declare #date datetime
while(#count <= #maxDays )
begin
if (DATENAME(dw, #date) = 'Saturday' OR DATENAME(dw, #date) = 'Sunday')
BEGIN
set #count = #count + 1
CONTINUE
END
set #date = DATEADD(d,#count, #startDate)
if (len(#csv) > 0) set #csv = #csv + ','
set #csv = #csv + DATENAME(day,#date) + '-' + DATENAME(month,#date)
set #count = #count + 1
end
return #csv
end
plug it into your select as CSVDates(vt.StartDate, vt.EndDate)
if you have a lot of dates in between, nvarchar(4000) may not be enough...

I figured out what was going wrong as finally I had time to work on this. Basically the block under weekend was not allowing date to get incremented which was resulting in the data not appearing.
Here is the working code for someone looking for similar ask
create function CSVDates (#startDate datetime, #endDate datetime)
returns nvarchar(4000)
as
begin
declare #csv nvarchar(4000) = ''
declare #maxDays int = DATEDIFF(DD, #startDate, #endDate)
declare #count int = 0
--assign start date
declare #date datetime = #startDate
while(#count <= #maxDays )
begin
if (DATENAME(dw, #date) = 'Saturday' OR DATENAME(dw, #date) = 'Sunday')
begin
--do nothing
set #count =#count
end
else
begin
if (len(#csv) > 0)
set #csv = #csv + ','
set #csv = #csv + DATENAME(day,#date) + '-' + SUBSTRING(DATENAME(month,#date),1,3)
end
set #count = #count + 1
set #date = DATEADD(d,#count, #startDate)
end
return #csv
end

Related

How to calculate number of days between two dates in Mysql excluding weekends (saturday and sunday)? [duplicate]

This question already has answers here:
MySQL function to find the number of working days between two dates
(39 answers)
Closed 4 years ago.
How do I return the number of days between two dates minus the number of saturday and sundays on that period ?
The DATEDIFF function on mysql gives me the number of days but doesnt exclude the weekends.
Example, I have two columns and want to add a third one that is the differente between the two.
I would appreciate any help.
Try using this
Declare #Date1 Datetime, #Date2 Datetime;
Select #Date1 = '8/1/2018', #Date2 = '8/7/2018'
Select Datediff(dd, #Date1 , #Date2) - (Datediff(wk, #Date1 , #Date2) * 2) -
Case When Datepart(dw, #Date1) = 1 Then 1 Else 0 End +
Case When Datepart(dw, #Date2) = 1 Then 1 Else 0 End
DROP FUNCTION IF EXISTS GetNumberOfDays;
CREATE FUNCTION GetNumberOfDays(P_Date1 varchar(20), P_Date2 varchar(20))
RETURNS int(100)
BEGIN
DECLARE x INT;
DECLARE V_Date1 date;
DECLARE V_Date2 date;
SET V_Date1 := STR_TO_DATE(P_Date1, '%d/%m/%Y');
SET V_Date2 := STR_TO_DATE(P_Date2, '%d/%m/%Y');
SET x := 0;
WHILE V_Date1 <= V_Date2
DO
IF (DAYOFWEEK(V_Date1) != 7 AND DAYOFWEEK(V_Date1) != 1)
THEN
BEGIN
SET x = x + 1;
END;
END IF;
SET V_Date1 := DATE_ADD(V_Date1, INTERVAL 1 DAY);
END WHILE;
RETURN x;
END;
SELECT GetNumberOfDays('01/08/2018', '11/08/2018')

Check Each Date In Date Range

In SQL Server 2008 I have a startdate and an enddate being passed to my procedure. I need to check each date in the range to see if it exists in my validworkday table. I have no clue where to begin on this, but this is how start/end day are set-up
Declare #startdate date, #enddate date
Set #startdate = '01/01/2015'
Set #enddate = '04/16/2015'
Now how can I iterate each date in this span to see if validworkday = true for it? The check I would need to run is like so (checking each date)
Select isvalidworkday
from validworkdays
where date = '01/01/2015'
Select isvalidworkday
from validworkdays
where date = '01/02/2015'
This is syntax that I found from #Incidently years ago (I don't remember where that original post is, but hopefully this will be enough to give the credit), that I still use today. All I did was slightly tweak his syntax to insert the data into a temp table and add a cursor to iterate each individual date.
DECLARE #DateFrom smalldatetime, #DateTo smalldatetime, #firstdate date;
SET #DateFrom='20000101';
SET #DateTo='20081231';
-------------------------------
WITH T(date)
AS
(
SELECT #DateFrom
UNION ALL
SELECT DateAdd(day,1,T.date)
FROM T
WHERE T.date < #DateTo
)
SELECT date
INTO #AllDates
FROM T OPTION (MAXRECURSION 32767);
Declare c1 Cursor For
Select date
FROM #AllDates
Open c1
Fetch Next From c1 Into #firstdate
While ##FETCH_STATUS = 0
Begin
--Do whatever processing you need here
Fetch Next From c1 Into #firstdate
End
Close c1
Deallocate c1
Code should only live in one place and not be rewritten. Create functions (once) like GetAllIntsBetween(), GetAllMonths(), GetAllDates(), etc. Then used them like:
DECLARE #startdate date = '01/01/2015', #enddate date = '04/16/2015'
SELECT allDates.TheDate,
isnull(v.isvalidworkday, false) AS isvalidworkday
FROM dbo.GetAllDates(#startdate, #enddate) AS allDates
LEFT JOIN validworkdays AS v
ON allDates.TheDate = v.MyDate
The GetAllDates() would be:
CREATE FUNCTION dbo.GetAllDates(#Start DATETIME, #End DATETIME)
RETURNS
#AllDates TABLE
(
TheDate DATETIME
)
AS
BEGIN
IF #Start > #End
BEGIN
DECLARE #Temp DATETIME
SET #Temp = #Start
SET #Start = #End
SET #End = #Temp
END
WHILE #Start <= #End
BEGIN
INSERT INTO #AllDates
VALUES(#Start)
SET #Start = DATEADD(DAY, 1, #Start)
END
RETURN
END
(note: can change DATETIME to DATE)

Date Wise Report in SQL server 2008

How to get following output ?
[1],[2],[3],[4],[5],[6],[8],[9],[10],[11],[12],[13],[14],[15],[16],[17]
,[18],[19],[20]
,[21],[22],[23],[24],[25],[26],[27],[28],[29],[30]
Need to fetch all dates from given month in sql server
I want to display daily Date Wise report
Example :
If I pass date as '11/01/2012' then it should return above result
and if I pass December than 31 days.
Very unclear question but try
DECLARE #epoch DATETIME = '20130101'
;WITH cte AS
(
SELECT #epoch DateKey
UNION ALL
SELECT DATEADD(D, 1, DateKey)
FROM cte
WHERE MONTH(DATEADD(D, 1, DateKey))=MONTH(#epoch)
)
SELECT * FROM cte
try below code
declare #date datetime = '09/10/2012'
declare #noofdays int
select #noofdays =datediff(day, #date, dateadd(month, 1, #date))
DECLARE #startDate DATETIME=CAST(MONTH(#date) AS VARCHAR) + '/' + '01/' + + CAST(YEAR(#date) AS VARCHAR) -- mm/dd/yyyy
DECLARE #endDate DATETIME= CAST(MONTH(#date) AS VARCHAR) + '/' + cast(#noofdays as varchar) + '/' + CAST(YEAR(#date) AS VARCHAR)
;WITH Calender AS
(
SELECT #startDate AS CalanderDate
UNION ALL
SELECT CalanderDate + 1 FROM Calender
WHERE CalanderDate + 1 <= #endDate
)
SELECT [Date] = CONVERT(VARCHAR(10),CalanderDate,25)
FROM Calender
OPTION (MAXRECURSION 0)
I am able to find out answer my self....
Thanks Buddy for trying to help me...
DECLARE #COLSPIVOT AS NVARCHAR(MAX)=''
declare #MaxDate int
set #MaxDate=(SELECT day(DATEADD(ms,-2,DATEADD(MONTH, DATEDIFF(MONTH,0,'8/1/2013')+1,0)))
AS [Current Month])
declare #i int =1
while (#i<=#MaxDate)
begin
set #COLSPIVOT=#COLSPIVOT+'['+convert(varchar(10),#i)+']'
if(#i!=#MaxDate)
begin
set #COLSPIVOT=#COLSPIVOT+','
end
set #i=#i+1
end
select #COLSPIVOT

Stripping the time out of datetime SQL Server 2005

I think I'm going crazy here.
I am trying to do a SP on SQL Server 2005 which takes a date, looks it up in another table and assigns a period number and week number (for financial calendar purposes).
The output needs to hold the date as a string, rather than datetime.
I simply CANNOT get the date to show without the time behind it.
I have tried a couple of methods:
select cast(floor(cast(#CalcDate as float)) as datetime)
I have made a function which converts it into a string and puts it back out again:
CREATE FUNCTION dbo.DateToVarchar (#DateIn datetime)
RETURNS varchar(10)
AS
BEGIN
declare #DD [varchar] (2)
declare #MM [varchar] (2)
declare #YYYY [varchar] (4)
declare #DateOut [varchar] (10)
declare #DDLen [int]
declare #MMLen [int]
set #DD = datepart(dd,#DateIn)
set #DDLen = len(#DD)
set #DD = (case when #DDLen < 2 then '0' + #DD else #DD end)
set #MM = datepart(mm,#DateIn)
set #MMLen = len(#MM)
set #MM = (case when #MMLen < 2 then '0' + #MM else #MM end)
set #YYYY = datepart(yyyy,#DateIn)
set #DateOut = #YYYY + '-' + #MM + '-' + #DD
return #DateOut
END
When I run the above function outside of the SP I get the date back just fine. When I run it through the SP it comes back as 2012-12-30 00:00:00.000
The variable #CalcDate is declared as a varchar(10)
Any ideas?
Thanks in advance
EDIT
Here is the body of the SP so far:
declare #StartDate [datetime]
, #EndDate [Datetime]
, #CalcDate [datetime] --This number will change in the WHILE loop to reflect the increment of days
, #Week [varchar]
, #Period [varchar]
, #i [int]
, #Year [int]
, #CalcDay [int]
, #CalcMonth [int]
, #CalcYear [int]
, #ConcatDate [char] (10)
set #StartDate = '2012-12-30'
set #EndDate = '2013-01-28'
set #Year = 2013
set #i = -1
-- Going to do a while loop here and instead of Week number and Period Number I'm going to do some calculations
set #Week = (Select WeekNum from aaGreensPeriodListTest Where PeriodNum = 1 and WeekNum = 1)
set #Period = (Select PeriodNum from aaGreensPeriodListTest Where PeriodNum = 1 and WeekNum = 1)
set #CalcDate = #StartDate + #i
set #CalcMonth = datepart(mm,#calcdate)
insert into aaGreensPeriodTest(RealDate,GreensYear,GreensPeriod,GreensWeek)
values (#CalcDate,#Year,#Period,#Week)
select #CalcDate as CalcDate, #CalcMonth as CalcMonth
SQL Server 2005 does not support date type without time part.
If your need to get date as a string you can use convert function. For example:
declare #date datetime;
set #date = getdate();
select convert(varchar, #date, 101) -- that will return date in ‘mm/dd/yyyy’ format
If you need a datetime variable without time part for some calculations, you can use an expression below:
declare #date datetime;
set #date = getdate();
select dateadd(dd, datediff(dd, 0, #date), 0)
As per http://msdn.microsoft.com/en-ca/library/ms187928.aspx, you cannot cast float->date directly. It's simply not supporte. But you can cast a datetime->date, so you'll have to double-cast. Or given your example, triple-cast:
CAST(CAST(CAST(#CalcDate AS float) AS datetime) AS date)

INSERT INTO dynamically added columns

Running SQL Server 2005/2008, I am rewriting my query to be cleaner and more compliant to not include bad habits. I used to have lots of IF statements and PIVOT to do this, but found a better way to achieve it now and just need a last bit to make it almost perfect.
DECLARE #startdate DATETIME;
DECLARE #enddate DATETIME;
DECLARE #showstore INT;
DECLARE #showcashier INT;
DECLARE #showregister INT;
DECLARE #showdate INT;
DECLARE #sql NVARCHAR(MAX);
DECLARE #result0 NVARCHAR(MAX);
SET #startdate = '1/1/2012';
SET #enddate = '2/28/2013';
SET #showdate = 1;
SET #showstore = 0;
SET #showcashier = 1;
SET #showregister = 0;
SET #startdate = DATEADD(DAY, DATEDIFF(DAY, 0, #startdate), 0);
SET #enddate = DATEADD(DAY, DATEDIFF(DAY, 0, #enddate), 0);
SET #sql = N'CREATE TABLE ##a13 (' + SUBSTRING(
CASE WHEN #showdate = 1 THEN ',[Transaction Date] DATETIME' ELSE '' END +
CASE WHEN #showstore = 1 THEN ',[Store ID] VARCHAR(10)' ELSE '' END +
CASE WHEN #showcashier = 1 THEN ',[Cashier] VARCHAR(100)' ELSE '' END +
CASE WHEN #showregister = 1 THEN ',[Register] VARCHAR(20)' ELSE '' END, 2, 2000);
DECLARE myCursor CURSOR FOR
SELECT DISTINCT c.CurrencyDesc
FROM dbo.Currencies AS c INNER JOIN dbo.rpPay AS p ON c.POSCurrency = p.PayType
INNER JOIN dbo.RPTrs AS r ON r.ReceiptNO = p.ReceiptNo
WHERE
c.CurrencyDesc <> 'Testing' AND c.CurrencyDesc <> 'Cash Change' AND
r.TRSDate >= #startdate AND r.TRSDate <= #enddate
OPEN myCursor
FETCH NEXT FROM myCursor INTO #result0
WHILE ##FETCH_STATUS = 0
BEGIN
SET #sql = #sql + ',[' + #result0 + '] INT'
FETCH NEXT FROM myCursor INTO #result0
END
CLOSE myCursor
DEALLOCATE myCursor
SET #sql = #sql + ')'
EXECUTE sp_executesql #sql, N'#startdate DATETIME,
#enddate DATETIME',#startdate, #enddate;
SET #sql = 'SELECT * FROM ##a13; DROP TABLE ##a13'
EXECUTE sp_executesql #sql
This Returns a table empty of rows. (know that the Currencies tables has more CurrencyDesc then shown here because these are just the ones used in the date range provided)
Which is exactly what I expect from it. Great so far so good. Now I need to add rows of data to it based on a Date Range (#startdate >= and <= #enddate) and depending on what they have checked off from the 4 possible options (#showstore, #showcashier, #showdate, #showregister)
Example : Date from 1/1/2013 till 2/28/2013 and show Register only (as seen in the picture) should have this DATA :
| Register | Cash | House Acct | MasterCard | Visa/MC
--------------------------------------------------------
1 | 01 | 20.00 | 235.25 | 1235.32 | 135.23
2 | 02 | 30.00 | 3542.42 | 323.52 | 523.64
3 | 03 | 23.35 | 100.32 | 3267.24 | 235.25
Reason for 2005/2008 is because some of the clients this is executed against, still use 2005 and in order to use PIVOT I would have to change the compatibility level on each database that is 2005.
PS. Before I get yelled at again, if I use #a13 instead of the global ##a13 it gives me
Msg 208, Level 16, State 0, Line 1
Invalid object name '#a13'.
What can I do about that so I don't use global temp tables?
If I am incorrect here, please clarify.
I BELIEVE you are asking how to populate a table with dynamic columns based on user input. The right answer here is, don't do that!
The best practice for this kind of thing is to have ALL the fields in your output table, then in your application/display layer you only show the fields that the user has requested.
Customizing a table layout within TSQL just to make a clean presentation introduces a lot of unnecessary complexity. This complexity comes with an increased performance cost as well.
If you have a static output table then it's trivial to return your data using the parameters given.