Stripping the time out of datetime SQL Server 2005 - function

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)

Related

SSRS show list of weeks

Is there a way I can create a list of weeks (param):w1,W2,... based on another param list (years), so the first list is for the years and the second is for the weeks corresponding to the chosen year.
For example if I choose 2017 from my first list my second list (weeks) should be updated with labels W1,W2,... & the values are the corresponding dates in the given year.
Try this ...
declare #year as int
declare #startdate as datetime
declare #wk as int
declare #endwk as datetime
declare #tbl as table (
tbl_wk int,
tbl_Monday datetime
)
set #endwk= (SELECT DATEPART(wk, GETDATE())+1)
set #wk = 1
set #year = '2017'
set #startdate = CAST (cast(#year as varchar(4))+ '/01/01 00:00:00' as datetime)
while (#wk < #endwk)
begin
insert into #tbl (tbl_wk,tbl_Monday)
select #wk,DATEADD(wk, DATEDIFF(wk,0,#startdate), 0) as monday--MondayOfCurrentWeek,
set #wk = #wk+1
set #startdate = #startdate+7
end
select * from #tbl
You could adapt this to create a table in SQL and then reference this in your report.
Note: You could include Year in an outer loop if you need dates from more than one year
declare #year as int
declare #startdate as datetime
declare #wk as int
declare #tbl as table (
tbl_wk int,
tbl_Monday datetime
)
set #wk = 1
set #year = '2017'
set #startdate = CAST (cast(#year as varchar(4))+ '/01/01 00:00:00' as datetime)
while (#wk < 53)
begin
insert into #tbl (tbl_wk,tbl_Monday)
select #wk,DATEADD(wk, DATEDIFF(wk,0,#startdate), 0) as monday--MondayOfCurrentWeek,
set #wk = #wk+1
set #startdate = #startdate+7
end
select * from #tbl

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)

How many equal days are between two date ranges, SQL

I have table with date ranges, like this:
DATE DATE2
14.03.2013 17.03.2013
13.04.2013 02.05.2013
I have to create a procedure, that returns day count that is equal to two date ranges, one which is in the table and another one.
Forexample, I have date range in the table like this 14.03.2013 - 17.03.2013 and another one, which is declared in procedure like this 02.03.2013 - 16.03.2013, so in this case day count would be 3, because, both date ranges have dates between 14.03.2013 and 16.03.2013.
suppose your table is called daterange and you have parameters defined #param1 and param2 in your procedure then something on these lines should work:
set #param1 := cast('2013-03-14' as date);
set #param2 := cast('2013-03-16' as date);
select
datediff(least(date2,#param2),#param1)+1
from daterange where #param1 between date1 and date2
See example in sqlfiddle
You should be able to adapt this T-SQL function to MySQL
IF EXISTS (SELECT * FROM sys.objects WHERE object_id = OBJECT_ID(N'[dbo].[fu_RPT_OverlappingDateRangesDays]') AND type in (N'FN', N'IF', N'TF', N'FS', N'FT'))
DROP FUNCTION [dbo].[fu_RPT_OverlappingDateRangesDays]
GO
-- ======================================================================================================================
-- Author: Stefan Steiger
-- ALTER date: 11.06.2015
-- Alter date: 11.06.2015
-- Description: Calculate the number of overlapping days in two date-ranges
-- http://stackoverflow.com/questions/20836429/how-to-gets-the-number-of-overlapping-days-between-2-ranges
-- ======================================================================================================================
-- DECLARE #firstStart datetime
-- DECLARE #firstEnd datetime
-- DECLARE #secondStart datetime
-- DECLARE #secondEnd datetime
-- SET #firstStart = '01.01.2015'
-- SET #firstEnd = '31.01.2015'
-- SET #secondStart = '15.01.2014'
-- SET #secondEnd = '15.02.2015'
-- SELECT dbo.fu_RPT_OverlappingDateRangesDays( #firstStart, #firstEnd, #secondStart, #secondEnd )
CREATE FUNCTION [dbo].[fu_RPT_OverlappingDateRangesDays]
(
#firstStart datetime
,#firstEnd datetime
,#secondStart datetime
,#secondEnd datetime
)
RETURNS integer
AS
BEGIN
DECLARE #maxStart datetime
DECLARE #minEnd datetime
DECLARE #interval int
IF #firstStart IS NULL OR #firstEnd IS NULL OR #secondStart IS NULL OR #secondEnd IS NULL
-- RETURN 0
RETURN NULL
IF #firstEnd < #firstStart
RETURN 0
IF #secondEnd < #secondStart
RETURN 0
SET #maxStart = #secondStart
SET #minEnd = #secondEnd
IF #firstStart > #secondStart
SET #maxStart = #firstStart
IF #firstEnd < #secondEnd
SET #minEnd = #firstEnd
-- PRINT #maxStart
-- PRINT #minEnd
--SET #interval = DATEDIFF(DAY, #maxStart, #minEnd) + 1
SET #interval = {fn timestampdiff(SQL_TSI_DAY, #maxStart, #minEnd)} + 1
IF #interval < 0
SET #interval = 0
-- PRINT #interval
RETURN #interval
END
GO

Getting dates between specific dates comma-separated

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

SSRS String -vs- Data Integer

I am working on a SSRS report and using a parameter that allows you to choose multiple options. However, when I do this I get an error that states:
Error Converting Data Type nVarChar to Int.
The data in the database is an Integer. The parameter is set up as an Integer and it works great when only choosing one option. The issue comes when I choose multiple options.
My co-worker came up with one work-around but I would like something a little more elegant and easier to plug in if possible.
Here is his work-around:
ALTER PROCEDURE [dbo].[DtaPrep_MktgClients]
#BegDate date = NULL
, #EndDate date = NULL
, #Species varchar(50) = 'canine,feline,K9,'
 , #HospList varchar(500) = NULL
This is where the hospmastid string gets converted into a temp table
/*
--===================================--
HOSPITALS SETUP
--===================================--
*/
If #HospList IS NOT NULL
BEGIN
DECLARE #WorkHospList varchar(500)
SET #WorkHospList = #HospList
;
CREATE TABLE #HospList
( HospID smallint NULL )
SET #CommaLoc = charindex(',', #WorkHospList)
WHILE #CommaLoc > 1
BEGIN
SET #curVal = LEFT(#WorkHospList, #commaloc-1 )
INSERT INTO
#HospList( HospID )
SELECT #curVal
SET #WorkHospList = substring( #WorkHospList, #commaloc+1, len(#WorkHospList) )
SET #CommaLoc = charindex(',', #WorkHospList)
END
END
This is using the temp table to accomplish the same thing as a “WHERE Hospmastid IN (101,102,103)…”
Method 1
SELECT
HospitalMasterID
, ClientID
, FirstName
, LastName
FROM
Client
WHERE
HospitalMasterID IN (Select HospID From #HospList )
Needless to say, I am sure there is a better way to accomplish this. If anyone has any ideas, please let me know.
Here is the full Query I am now using. But it is not selecting anything so there is an issue with the Created Table.
USE [xxxxx]
GO
/****** Object: StoredProcedure [dbo].[PriceErosion] Script Date: 11/26/2013 8:26:33 AM ******/
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
/*
-- =============================================
-- Author:
-- Create date: 11/25/2013
-- Description: Determines the products in which the price was lowered and revenue lost during a set time period.
-- =============================================
*/
--#StartDate as Date = Null
--,#EndDate as Date = Null
--,#CurDate as Date = Null
--,#Hospital as VarChar = Null
--,#Division as Int = Null
Declare #StartDate as Date = Null
Declare #EndDate as Date = Null
Declare #Hospital as Int = Null
Declare #Division as Int = Null
DECLARE #curDate Date = Null
SET #curDate = GETDATE()
Set #StartDate = CASE WHEN #StartDate IS NULL THEN DATEADD(dd, -31, Dateadd(dd, -1, #curdate) ) ELSE #StartDate END
Set #EndDate = CASE WHEN #EndDate IS NULL THEN Dateadd(dd, -1, #curdate) ELSE #EndDate END
Set #Hospital = Case When #Hospital IS Null Then '3' Else #Hospital End;
IF OBJECT_ID('tempdb.dbo.#HospList') IS NOT NULL DROP TABLE #HospList ;
If #Hospital IS NOT NULL
BEGIN
DECLARE #WorkHospList varchar(500)
Declare #CommaLoc as Int
Declare #curVal as int
SET #WorkHospList = #Hospital
;
CREATE TABLE #HospList
( HospID smallint NULL )
SET #CommaLoc = charindex(',', #WorkHospList)
WHILE #CommaLoc > 1
BEGIN
SET #curVal = LEFT(#WorkHospList, #commaloc-1 )
INSERT INTO
#HospList( HospID )
SELECT #curVal
SET #WorkHospList = substring( #WorkHospList, #commaloc+1, len(#WorkHospList) )
SET #CommaLoc = charindex(',', #WorkHospList)
END
END
Begin
-- Sets the Baseline Price Date in the PriceChangeHistory Table.
With PC1
as
(Select
HospitalMasterID
,TxnCode
,UserInfoMasterID
,Active
,min(TxnDateTime) as StartingDate
From
PriceChangeHistory
Where
TxnDateTime Between #StartDate and #EndDate
Group By
HospitalMasterID, TxnCode, UserInfoMasterID, Active)
-- Gets the Baseline Price for the period from the PriceChangeHistory Table
,PC
as
(Select
PC1.HospitalMasterID
,PC1.TxnCode
,PC1.UserInfoMasterID
,PC1.Active
,Cast (PC1.StartingDate as Date) as StartingDate
,PC2.OldPrice as StartingPrice
,PC2.NewPrice
,PC2.TxnSubType
From
PC1
Inner Join
PriceChangeHistory as PC2
On
PC1.HospitalMasterID = PC2.HospitalMasterID
and
PC1.TxnCode = PC2.TxnCode
and
PC1.StartingDate = PC2.TxnDateTime
Where
PC2.OldPrice > PC2.NewPrice)
--MedicalHistory Information
,MH
as
(Select
HospitalMasterID
,PatientID
,TxnDate
,TxnCode
,Description
,ListAmount
,ExtendedAmount
,TxnType
,Quantity
,(Case
When Quantity <> '1' Then (ListAmount/Quantity)
Else ListAmount
End) as UnitPrice
From
MedicalHistory
Where
TxnDate Between #StartDate and #EndDate
and
_IsServOrITem = 1)
-- Determines the Revenue lost per each sale, also reduces the results to only those items where the Price was lowered not raised.
,RL
as
(Select
PC.HospitalMasterID
,MH.PatientID
,PC.TxnCode
,PC.TxnSubType
,MH.Description
,PC.UserInfoMasterID as ChangedByUserID
,MH.TxnDate
,PC.StartingPrice
,Cast (MH.UnitPrice as Money) as UnitPrice
,Cast ((StartingPrice - UnitPrice) as Money) as RevenueLost
From
PC
Left OUter Join
MH
on
PC.HospitalMasterID = MH.HospitalMasterID
and
PC.TxnCode = MH.TxnCode
Where
PC.StartingPrice > MH.UnitPrice)
--- Determine the name of the tech changing the prices.
,UI
as
(Select
HospitalMasterID
,UserInfoMasterID
,Name
From
UserInfo)
--- Get the Division and Hospital Name for each Hospital.
,HODI
as
(Select
DI.DivisionID
,DI.DivisionName
,HO.HospMastID
,HO.HospCode
,HO.HospName
From
ref_Hospital as HO
inner Join
ref_Division as DI
on
HO.DivisionID = DI.DivisionID)
,HI
as
(Select
HODI.DivisionID
,HODI.DivisionName
,RL.HospitalMasterID
,HODI.HospCode
,HODI.HospName
,RL.PatientID
,RL.TxnCode
,RL.TxnSubType
,RL.Description
,RL.ChangedByUserID
,RL.TxnDate
,RL.StartingPrice
,RL.UnitPrice
,RL.RevenueLost
From
RL
Left Outer Join
HODI
ON
RL.HospitalMasterID = HODI.HospMastID
Where
TXNDate Between #StartDate and #EndDate)
Select
*
From
HI
Where
HospitalMasterID in (Select HospID from #Hosplist)
Order By
HOspitalMasterID
end
Prior to SQL Server 2008, the standard way to filter by one or more values was to pass an XML document to the Stored Procedure and join on it. In this case, you could pass the data as a string with the integers separated by commas, then convert that into an XML document, then join on the XML. So you should change the multiselect in SSRS to a text datatype. Here's a post that shows you how to open an XML document: http://blog.sqlauthority.com/2009/02/13/sql-server-simple-example-of-reading-xml-file-using-t-sql/
SQL Server 2008 lets you use table-valued parameters, but again, it might be best to pass the data as a string of comma separated integers and then let the stored procedure put the data into a table-valued parameter, and then join on that. Here's a post that describes how to use table valued parameters: http://blog.sqlauthority.com/2008/08/31/sql-server-table-valued-parameters-in-sql-server-2008/