I wrote a query
WITH sample AS (
SELECT CAST('2010-01-01' AS DATETIME) AS d
UNION ALL
SELECT DATEADD(dd, 1, i.vrp_notificationdate) as deneme
FROM Incident i
WHERE DATEADD(dd, 1, i.vrp_notificationdate) <= CAST('2011-11-01' AS DATETIME))
SELECT count(DATENAME(mm,l.vrp_notificationdate) +' '+DATENAME(yy,l.vrp_notificationdate)) as Toplam,DATENAME(mm,l.vrp_notificationdate) +' '+DATENAME(yy,l.vrp_notificationdate)
FROM Incident as l
group by
DATENAME(mm,l.vrp_notificationdate) +' '+DATENAME(yy,l.vrp_notificationdate)
the query show
10 November 2011
101 October 2011
4 September 2011
but i want to show this .
0 january 2010
0 february 2010
-
-
-
10 November 2011
101 October 2011
4 september 2011
0 december 2011
0 february 2011
i tried case when statement,but query show same result
How to solve what i use
Best regards.
You are trying to show data that doesn't exist. The idea of this solution is to
Add dummy dates
Assign a count of 0 to each dummy date
Union your original results with this dummy dates
Group into a final result
SQL Statement
DECLARE #StartDate DATE = '01-01-2010'
;WITH Dates(d) AS (
SELECT #StartDate
UNION ALL
SELECT DATEADD(mm, 1, d) AS Date
FROM Dates
WHERE d < '12-01-2012'
)
,WITH sample AS (
SELECT CAST('2010-01-01' AS DATETIME) AS d
UNION ALL
SELECT DATEADD(dd, 1, i.vrp_notificationdate) as deneme
FROM Incident i
WHERE DATEADD(dd, 1, i.vrp_notificationdate) <= CAST('2011-11-01' AS DATETIME)
)
SELECT SUM(Toplam) AS Toplam
, DateFormat
FROM (
SELECT COUNT(DATENAME(mm,l.vrp_notificationdate) + ' ' + DATENAME(yy,l.vrp_notificationdate)) AS Toplam
, DATENAME(mm,l.vrp_notificationdate) + ' ' + DATENAME(yy,l.vrp_notificationdate) AS DateFormat
, CONVERT(VARCHAR(6), l.vrp_notificationdate, 112) as orderDate
FROM Incident as l
GROUP BY
DATENAME(mm,l.vrp_notificationdate) + ' ' + DATENAME(yy,l.vrp_notificationdate)
, CONVERT(VARCHAR(6), l.vrp_notificationdate, 112)
UNION ALL
SELECT 0 AS Toplam
, DATENAME(mm, d) + ' ' + DATENAME(yy, d)
, CONVERT(VARCHAR(6), d.d, 112) as orderDate
FROM Dates d
) g
GROUP BY
DateFormat
ORDER BY
g.orderDate
Well, if the date doesn't appear, it means that there isn't any value present for that date. So, it's impossible to get that date to appear in the result.
To pass this the simplest solution is to:
Create a table with all the possible dates and another column that will start with zero.
Update that table with the results of the query that you made (update the column that start with zero to have the count values).
Display the end results from the new table:
select countValues + ' ' + dateValues from newTable
If you have any doubt, just ask :)
Why do you provide "WITH sample AS" when you do not use sample?
I'ld use this recursive query to build all dates for your result table.
WITH sample (d) AS (
SELECT CAST('2010-01-01' AS DATETIME)
UNION ALL
SELECT DATEADD(mm, 1, d) FROM sample WHERE DATEADD(mm, 1, d) <= CAST('2011-11-01' AS DATETIME)
)
select * from sample
You could then outer join this table with your Incident table to get the count of incidents for each month.
If you want to see a lot of months or even days, you might get an MSG 530 because of too much recursion. In this case you need the add OPTION (MAXRECURSION ) after "select * from sample".
Related
If a user selects a range such as:
Start: November 2016
End: September 2017,
I want to include all results that fall within the range of 2016-11-01 to 2017-09-30.
I tried concatenating together the year, month, and day, however the issue comes that not all months have the same last day. While I know all months start on day 01, a month's end day can be 28, 29, 30, or 31.
Is there a way to do this without constructing the date? SqlServer 2008 doesn't have the EOMONTH function, and I feel like anything more complex than that is not the right solution. I would like to avoid this:
WHERE
DateCol >= '2016' + '-' + '11' + '-01' AND
DateCol <= '2017' + '-' + '09' + '-30'
It really seems to me that the easiest and best answer is to go from the first of the beginning month to the first of the month after the ending month, and make the second comparison not inclusive.
In other words, instead of this:
WHERE
DateCol >= '2016' + '-' + '11' + '-01' AND
DateCol <= '2017' + '-' + '09' + '-30'
simply this:
WHERE
DateCol >= '2016' + '-' + '11' + '-01' AND
DateCol < '2017' + '-' + '10' + '-01'
There is a faster way to do so :
DECLARE #minDate DATE
DECLARE #maxDate DATE
SET #minDate = XXXXX
SET #maxDate = YYYYY
-- Get the first day of the month minDate.
SET #minDate = CONVERT(datetime,CONVERT(varchar(6),#minDate,112)+'01',112)
-- Get the last day of the month minDate.
SET #maxDate = CONVERT(datetime,CONVERT(varchar(6),#maxDate,112)+'01',112)
SET #maxDate = DATEADD(day, -1, DATEADD(month, 1, #maxDate))
SELECT * FROM myTABLE WHERE DateCol >= #minDate AND DateCol <= #maxDate
Or :
SELECT * FROM myTABLE
WHERE DateCol >= CONVERT(datetime,CONVERT(varchar(6),XXXXX,112)+'01',112)
AND DateCol <= DATEADD(day, -1, DATEADD(month, 1, CONVERT(datetime,CONVERT(varchar(6),YYYYY,112)+'01',112)))
Use syntax like CONVERT(datetime,'20170930',112) or CONVERT(datetime,'09-30-2017',110) for XXXXX and YYYYY rather than '2017-09-30' that use SQL Server implicit convertion from char to datetime (rely on the server configuration : can be hazardous!!!)).
Using this syntax is faster because #minDate and #maxDate do not need any evaluation. So that indexes can be used directly...
Otherwise a scalar function that will simulate the eomonth() behaviour could be usefull...
You could use following select statement to get last date of any month (and any year) by passing a field or date to it:
DECLARE #dtDate DATE
SET #dtDate = '09/25/2016'
SELECT CAST(DATEADD(s,-1,DATEADD(mm, DATEDIFF(m,0,#dtDate)+1,0)) AS DATE) AS LastDay_AnyMonth
Please provide some example data and desired result and I will update my answer further.
Here you go:
DECLARE #YourTable TABLE (YourData DATE);
INSERT INTO #YourTable VALUES
('2016-11-01'),
('2016-09-05'),
('2017-03-03'),
('2017-11-11'),
('2017-12-14'),
('2017-09-30');
WITH CTE AS (
SELECT YourData
FROM #YourTable
WHERE YEAR(YourData) =2016 AND MONTH (YourData) >= 11
)
SELECT YourData
FROM #YourTable
WHERE YEAR(YourData) =2017 AND MONTH (YourData) <= 9
UNION ALL
SELECT YourData
FROM CTE;
There is no need to know the end of the month (28 or 30 or 31).
For 2008, you can simply convert the string
Example
Select Date1=convert(date,'November 2016')
,Date2=dateadd(DAY,-1,dateadd(MONTH,1,convert(date,'September 2017')))
Returns
Date1 Date2
2016-11-01 2017-09-30
So the WHERE would be somthing like this
...
Where DateCol between convert(date,'November 2016')
and dateadd(DAY,-1,dateadd(MONTH,1,convert(date,'September 2017')))
A useful construct for performing date-based operations is to make use of a Date Dimension table. You are creating a lookup table that is populated with a lot of information about dates over a large span of time. You can then query the table based on the information that you do have. The table is small enough so that it does not impose significant performance concerns.
In your particular case, you have the month and year. You would plug that into the date dimension table to get the first of the month from the beginning month and the last of the month from the ending month. You now have a time range to search over without any complex logic or calculations on the fly.
Aaron Bertrand explains it in depth here: https://www.mssqltips.com/sqlservertip/4054/creating-a-date-dimension-or-calendar-table-in-sql-server/
I have a little issue with one my queries. The entire query is actually is a little long since it includes a UNION ALL.
SELECT 'ITV' = CASE WHEN tblIntake.StaffID Is Null THEN '<Unknown>' ELSE
(tblStaffMember.StaffLast + ', ' + tblStaffMember.StaffFirst + CASE WHEN
tblStaffMember.StaffMI Is Null THEN '' ELSE ' ' + tblStaffMember.StaffMI END) END,
tblMember.[LAST], tblMember.[FIRST],
'DueDate' = DATEADD(m, 6,CAST(CONVERT(Varchar(10),
MONTH(tblIntake.EnrollDate)) + '/' + CONVERT(Varchar(10),
DAY(tblIntake.EnrollDate)) + '/' + CONVERT(Varchar(10),YEAR(GETDATE()))As
DateTime)), 'Type' = '6 Month Appt'
From tblIntake LEFT JOIN tblStaffMember ON tblIntake.StaffID =
tblStaffMember.StaffID LEFT JOIN tblMember ON
tblIntake.KEY = tblMember.KEY
Where tblIntake.UnEnrollDate Is Null AND
DATEADD(m,6,CAST(CONVERT(Varchar(10),MONTH(tblIntake.EnrollDate)) + '/' +
CONVERT(Varchar(10),DAY(tblIntake.EnrollDate)) + '/' +
CONVERT(Varchar(10),YEAR(GETDATE()))As DateTime)) > GETDATE() AND
DATEADD(m, 6,CAST(CONVERT(Varchar(10),MONTH(tblIntake.EnrollDate)) + '/' +
CONVERT(Varchar(10),DAY(tblIntake.EnrollDate)) + '/' +
CONVERT(Varchar(10),YEAR(GETDATE()))As DateTime)) <= DATEADD(d, 45, GETDATE())
So, I have this wonderful query. Everything was running okay until a user entered a leap year date for ENROLLDATE in tblIntake. How would I go about fixing it? My other UNION does the same SELECT statements with the exception of for when it does
CONVERT(VARCHAR(10),YEAR(GetDate()-1)) as DateTime > '4th line from the bottom
CONVERT(VARCHAR(10),YEAR(GetDate()-1)) as DateTime > '2nd line from the bottom
EDIT:
Receiving this error when I run the query
Msg 242, Level 16, State 3, Line 1
The conversion of a varchar data type to a datetime data type resulted in an out-of-range value.
I tried running the separate queries, and it seems like I'm only getting the error when I do this..
CONVERT(VARCHAR(10),YEAR(GetDate()-1)) as DateTime > '4th line from the bottom
CONVERT(VARCHAR(10),YEAR(GetDate()-1)) as DateTime > '2nd line from the bottom
After UNION ALL
EDIT 2:
I've been working off Sean's answer which makes more sense. Here is the code that I've got....
SELECT 'CSC' = case when tblIntake.staffID is null Then '<notIndicated>' Else (tblStaffMember.staffLast + ',' + tblStaffMember.StaffFirst + case when tblStaffMember.staffMI is null then '' else ' ' + tblStaffMember.staffMI END)end
, tblMember.[Last], tblMember.[First]
,'Due' = DateADD(m,6,cast(tblIntake.enrolldate as datetime))
,'Type' = '6 Month Review'
from tblMembEnrollment
left join tblStaffMember on tblIntake.staffID = tblStaffMember.staffID
left join tblMember on tblIntake.SBkey=tblMember.sbkey
where tblIntake.unEnrollDate is null and dateAdd(m, 6, tblIntake.enrolldate) > GETDATE()
and dateadd(m, 6, cast(tblIntake.enrolldate as DateTime))<= DateAdd(d,45,GetDate())
The issue I'm seeing is that in the old query, when the code takes apart the EnrollDate into days, months and years for years it used GET DATE, see below in between *** ****
Where tblIntake.UnEnrollDate Is Null AND
DATEADD(m,6,CAST(CONVERT(Varchar(10),MONTH(tblIntake.EnrollDate)) + '/' +
CONVERT(Varchar(10),DAY(tblIntake.EnrollDate)) + '/' +
CONVERT(Varchar(10),***YEAR(GETDATE()))As DateTime))*** > GETDATE()
Now it was easier done this way since he did take it apart, how is it that I can do it with my full Enroll date.
If I understand what you are trying to do here you can greatly simplify this. Please note that I used aliases everywhere instead of repeating the table name over and over. Also, I used the datepart names instead of the abbreviations as they are much more clear. Last but not least I just used the existing datetime value. I converted them to the date datatype as what it appears the existing logic is doing is converting it to a date value to avoid the time portion. This as fairly common prior to 2005 when the date datatype was added. I also reduced all the nested case expressions into something much easier to read.
SELECT 'ITV' = ISNULL(sm.StaffLast + ', ' + sm.StaffFirst + ISNULL(' ' + sm.StaffMI, ''), '<Unknown>')
, tblMember.[LAST]
, tblMember.[FIRST]
, 'DueDate' = DATEADD(month, 6, convert(date, tblIntake.EnrollDate))
, 'Type' = '6 Month Appt'
From tblIntake i
LEFT JOIN tblStaffMember sm ON i.StaffID = sm.StaffID
LEFT JOIN tblMember m ON i.KEY = m.KEY
Where i.UnEnrollDate Is Null
AND DATEADD(month, 6, convert(date, i.EnrollDate)) > GETDATE()
AND DATEADD(month, 6, convert(date, i.EnrollDate)) <= DATEADD(day, 45, GETDATE())
--EDIT--
With the clarity of rules I think this should be what you are looking for. This has the advantage of also being SARGable so that any index on i.EnrollDate can be utilized.
Where i.UnEnrollDate Is Null
AND convert(date, i.EnrollDate) > DATEADD(month, -6, GETDATE())
AND convert(date, i.EnrollDate) <= DATEADD(day, -45, GETDATE())
I'd replace all of those date parts and converts with dateadd, something like:
declare #test datetime
set #test = '2-29-2016'
select cast(#test as varchar(11))
, cast(dateadd(mm, 6, #test) as varchar(11))
, cast(dateadd(yy, -1, #test) as varchar(11))
If you keep the dates as datetimes, SQL server will automatically correct for leap years, shorter months, etc. The query above returns:
Feb 29 2016 Aug 29 2016 Feb 28 2015
I have a table that has one row per month and amounts are stored in different columns (DAY1, DAY2... DAY31). I have created a view that uses unpivot to split this into one row per day, so that I can do calculations for given date range.
When I try to use the view by selecting only certain date range, it ends up in error as long when I have DAY29..DAY31 in the table. If the table contains days only up to 28, then it works fine.
Unfortunately changing the table structure isn't really an option and I tried the same thing with inline function, but it ends up in the same error
Msg 242, Level 16, State 3, Line 52 The conversion of a nvarchar data
type to a datetime data type resulted in an out-of-range value.
This is my table:
CREATE TABLE CONSUMPTION (
ID int NOT NULL,
YEAR int NOT NULL,
MONTH int NOT NULL,
DAY1 int NULL,
DAY2 int NULL,
DAY3 int NULL,
DAY31 int NULL,
CONSTRAINT TEST_PK PRIMARY KEY CLUSTERED (ID, YEAR, MONTH)
)
insert into CONSUMPTION values (1,2015,1,10,20,30,310)
insert into CONSUMPTION values (1,2015,2,10,20,30,NULL)
This is my view:
create view CONSUMPTION_CALENDAR as
select
ID,
YEAR,
MONTH,
convert(datetime, substring(COLNAME, 4,2) + '.' + convert(varchar, [MONTH]) + '.' + convert(varchar, [YEAR]), 104) as CONSDATE,
CONSKG
from
(
select * from CONSUMPTION
) S
unpivot (CONSKG for COLNAME in (DAY1,DAY2,DAY3,DAY31)) as UP
go
If I run it just like this, it works fine:
select * from CONSUMPTION_CALENDAR
But if I add criteria, it returns the data, but also fails:
select * from CONSUMPTION_CALENDAR where CONSDATE >= '20150101'
Is there any workaround that I would be able to select just certain date range?
Edit: Data in the view:
ID YEAR MONTH CONSDATE CONSKG
1 2015 1 2015-01-01 10
1 2015 1 2015-01-02 20
1 2015 1 2015-01-03 30
1 2015 1 2015-01-31 310
1 2015 2 2015-02-01 10
1 2015 2 2015-02-02 20
1 2015 2 2015-02-03 30
Example in SQL Fiddle.
Option 1
Create a calendar table that has date in suitable format, e.g. D.M.YYYY that can be joined with the unpivot. This way there is no conversion from unpivot string to dates, so it cannot fail.
create view CONSUMPTION_CALENDAR as
select
P.ID,
C.DAY,
P.MONTH,
P.YEAR,
C.CALENDARDATE as CONSDATE,
P.CONSKG
from (
select
ID,
YEAR,
MONTH,
ltrim(substring(COLNAME, 4,2)) + '.' + convert(varchar(2), [MONTH]) + '.' + convert(varchar(4), [YEAR]) as STOCKDATESTR,
CONSKG
from
(
select * from CONSUMPTION
) S
unpivot
(CONSKG for COLNAME in (DAY1,DAY2,DAY3,DAY4,DAY5,DAY6,DAY7,DAY8,DAY9,DAY10,DAY11,DAY12,DAY13,DAY14,DAY15,DAY16,DAY17,DAY18,DAY19,DAY20,DAY21,DAY22,DAY23,DAY24,DAY25,DAY26,DAY27,DAY28,DAY29,DAY30,DAY31)) as UP
) P
join CALENDAR C on C.DATESTR = P.STOCKDATESTR
The CALENDAR table has dates in format D.M.YYYY without leading zeros in DATESTR and CALENDARDATE is Date.
Option 2
The fetch seems to work ok also with view like this, when NULLS are changed into 1.1.1900:
create view CONSUMPTION_CALENDAR as
select
ID,
YEAR,
MONTH,
convert(datetime,
case when CONSKG is NULL then '1.1.1900' else
substring(COLNAME, 4,2) + '.' + convert(varchar, [MONTH]) + '.' + convert(varchar, [YEAR]) end
, 104) as CONSDATE,
CONSKG
from
(
select * from CONSUMPTION
) S
unpivot (CONSKG for COLNAME in (DAY1,DAY2,DAY3,DAY4,DAY5,DAY6,DAY7,DAY8,DAY9,DAY10,DAY11,DAY12,DAY13,DAY14,DAY15,DAY16,DAY17,DAY18,DAY19,DAY20,DAY21,DAY22,DAY23,DAY24,DAY25,DAY26,DAY27,DAY28,DAY29,DAY30,DAY31)) as UP;
Assuming there's no bad data in the table, this shouldn't fail.
Option 3
I was able to find out one way to prevent the problem by using top. I assume SQL Server is not able to move the where predicate from outside the top into it because in theory it could change the results, even if there is no order by:
select * from (
select top 1000000000 * from CONSUMPTION_CALENDAR
) X
where CONSDATE >= convert(datetime, '20150101')
This seems to work ok, but can't be sure if this starts to fail in certain cases.
calculate the month difference between two dates
Its working fine with dateDiff(m, datestart , dateend ) but i have the scenario of calculate the month based on day.like if 01/01/2012 to 20/01/2012 must show as the result of 1 month.
and another scenario is 02/01/2012 to 03/02/102 must show the as the result of 2 months.
how can i do that.
Try This,
Declare #sDate date = '1/15/2014'
Declare #eDate date = '3/10/2014'
Select DATEDIFF(mm,#sDate,#eDate) - Case When datepart(DD,#sDate) > DATEPART(dd,#eDate) Then 1 else 0 end
SQL Fiddle DEMO
How about this,
SELECT CASE
WHEN
DATEPART(MONTH,'STARTDATE') = DATEPART (MONTH,'ENDDATE')
THEN
DATEPART(MONTH,'STARTDATE')
ELSE
DATEDIFF(MONTH,'STARTDATE','ENDDATE')
END
AS 'MONTH-DIFFERENCE'
FROM TABLE_NAME
I resolved it.
SELECT
BadgeNo AS [Badge No],
JB.GHRSBadgeNo AS [GHRS No],
(ISNULL(Emp.FirstName,'') + ' ' + ISNULL(Emp.MiddleName,'') + ' '+ ISNULL(Emp.LastName,'')) AS [Name],
JB.Department AS [Department],
JB.ServiceCompany AS [Service Company],
REPLACE(CONVERT(VARCHAR(11), Emp.BirthDate, 106), ' ', '-') AS [Birth Date]
FROM
Employee AS Emp
LEFT JOIN
jobdata AS JB
ON
EMP.BadgeNo = JB.BadgeNo
WHERE
1 = (FLOOR(DATEDIFF(dd,EMP.BirthDate,DATEADD(month, 1,GETDATE())) / 365.25))
-
(FLOOR(DATEDIFF(dd,EMP.BirthDate,GETDATE()) / 365.25))
Use the same function and Add 1 to the result
e.g.
(dateDiff(m, datestart , dateend )+1) as Month
I am currently working on a query that needs to calculate the difference in days between two different dates. I've had issues with our DATE columns before, because they are all being stored as numeric columns which is a complete pain.
I tried using CONVERT as I had done in the past to try and get the different pieces of the DATETIME string built, but I am not having any luck.
The commented line --convert(datetime,) is where I am having the issue. Basically, I need to convert PO_DATE and LINE_DOCK_DATE to a format that is usable, so I can calculate the difference between the two in days.
USE BWDW
GO
SELECT
[ITEM_NO]
,[ITEM_DESC]
,[HEADER_DUE_DATE]
,[BWDW].[dbo].[DS_tblDimWhs].WHS_SHORT_NAME AS 'Warehouse'
,[BWDW].[dbo].[DS_tblFactPODtl].[PO_NO] AS 'PO NUMBER'
,[BWDW].[dbo].[DS_tblFactPODtl].[PO_DATE] AS 'Start'
,[BWDW].[dbo].[DS_tblFactPODtl].[PO_STATUS] AS 'Status'
,[BWDW].[dbo].[DS_tblFactPODtl].[LINE_DOCK_DATE] AS 'End'
--,(SELECT CONVERT(DATETIME, CONVERT(CHAR(8), [BWDW].[dbo].[DS_tblFactPODtl].[PO_DATE])) FROM dbo.DS_tblFactPODtl)
FROM [BWDW].[dbo].[DS_tblFactPODtl]
INNER JOIN [BWDW].[dbo].[DS_tblDimWhs] ON [BWDW].[dbo].[DS_tblFactPODtl].WAREHOUSE = [BWDW].[dbo].[DS_tblDimWhs].WAREHOUSE
INNER JOIN [BWDW].[dbo].[DS_tblFactPO] ON [BWDW].[dbo].[DS_tblFactPODtl].PO_NO = [BWDW]. [dbo].[DS_tblFactPO].PO_NO
WHERE [BWDW].[dbo].[DS_tblFactPODtl].[PO_STATUS] = 'Closed'
AND [BWDW].[dbo].[DS_tblFactPODtl].[LINE_DOCK_DATE] <> 0
I have a snippet I saved from a previous project I worked on that needed to only display results from today through another year. That had a bunch of CAST and CONVERTS in it, but I tried the same methodology with no success.
In the long run, I want to add a column to each database table to contain a proper datetime column that is usable in the future... but that is another story. I have read numerous posts on stackoverflow that talk about converting to NUMERIC and such, but nothing out of a NUMERIC back to DATETIME.
Example data:
Start | End | Difference
--------------------------------
20110501 | 20111019 | 171
20120109 | 20120116 | 7
20120404 | 20120911 | 160
Just trying to calculate the difference..
MODIFIED PER AARON:
SELECT
FPODtl.[ITEM_NO] AS [Item]
,FPODtl.[ITEM_DESC] AS [Description]
,D.WHS_SHORT_NAME AS [Warehouse]
,FPODtl.[PO_NO] AS [PO NUMBER]
,FPODtl.[PO_DATE] AS [Start]
,FPODtl.[PO_STATUS] AS [Status]
,FPODtl.[LINE_DOCK_DATE] AS [End]
,DATEDIFF
(
DAY,
CASE WHEN ISDATE(CONVERT(CHAR(8), FPODtl.PO_DATE)) = 1
THEN CONVERT(DATETIME, CONVERT(CHAR(8), FPODtl.PO_DATE)) END,
CASE WHEN ISDATE(CONVERT(CHAR(8), FPODtl.[LINE_DOCK_DATE])) = 1
THEN CONVERT(DATETIME, CONVERT(CHAR(8), FPODtl.[LINE_DOCK_DATE])) END
)
FROM [dbo].[DS_tblFactPODtl] AS FPODtl
INNER JOIN [dbo].[DS_tblDimWhs] AS D
ON FPODtl.WAREHOUSE = D.WAREHOUSE
INNER JOIN [dbo].[DS_tblFactPO] AS FPO
ON FPODtl.PO_NO = FPO.PO_NO
WHERE FPODtl.[PO_STATUS] = 'Closed'
AND FPODtl.[LINE_DOCK_DATE] <> 0;
DECLARE #x NUMERIC(10,0);
SET #x = 20110501;
SELECT CONVERT(DATETIME, CONVERT(CHAR(8), #x));
Result:
2011-05-01 00:00:00.000
To compare two:
DECLARE #x NUMERIC(10,0), #y NUMERIC(10,0);
SELECT #x = 20110501, #y = 20111019;
SELECT DATEDIFF
(
DAY,
CONVERT(DATETIME, CONVERT(CHAR(8), #x)),
CONVERT(DATETIME, CONVERT(CHAR(8), #y))
);
Result:
171
More importantly, fix the table. Stop storing dates as numbers. Store them as dates. If you get errors with this conversion, it's because your poor data choice has allowed bad data into the table. You can get around that - potentially - by writing the old version of TRY_CONVERT():
SELECT DATEDIFF
(
DAY,
CASE WHEN ISDATE(col1)=1 THEN CONVERT(DATETIME, col1) END,
CASE WHEN ISDATE(col2)=1 THEN CONVERT(DATETIME, col2) END
)
FROM
(
SELECT
col1 = CONVERT(CHAR(8), col1),
col2 = CONVERT(CHAR(8), col2)
FROM dbo.table
) AS x;
This will produce nulls for any row where there is garbage in either column. Here is a modification to your original query:
SELECT
[ITEM_NO] -- what table does this come from?
,[ITEM_DESC] -- what table does this come from?
,[HEADER_DUE_DATE] -- what table does this come from?
,D.WHS_SHORT_NAME AS [Warehouse] -- don't use single quotes for aliases!
,FPODtl.[PO_NO] AS [PO NUMBER]
,FPODtl.[PO_DATE] AS [Start]
,FPODtl.[PO_STATUS] AS [Status]
,FPODtl.[LINE_DOCK_DATE] AS [End]
,DATEDIFF
(
DAY,
CASE WHEN ISDATE(CONVERT(CHAR(8), FPODtl.PO_DATE)) = 1
THEN CONVERT(DATETIME, CONVERT(CHAR(8), FPODtl.PO_DATE)) END,
CASE WHEN ISDATE(CONVERT(CHAR(8), FPODtl.[LINE_DOCK_DATE])) = 1
THEN CONVERT(DATETIME, CONVERT(CHAR(8), FPODtl.[LINE_DOCK_DATE])) END
)
FROM [dbo].[DS_tblFactPODtl] AS FPODtl
INNER JOIN [dbo].[DS_tblDimWhs] AS D
ON FPODtl.WAREHOUSE = D.WAREHOUSE
INNER JOIN [dbo].[DS_tblFactPO] AS FPO
ON FPODtl.PO_NO = FPO.PO_NO
WHERE FPODtl.[PO_STATUS] = 'Closed'
AND FPODtl.[LINE_DOCK_DATE] <> 0;
If the date stored as a number is like this: 20130226 for today, then the simpler way to convert to DATE or DATETIME would be:
SELECT CONVERT(DATETIME,CONVERT(VARCHAR(8),NumberDate),112)
Here is a quick formula to create a date from parts :
DateAdd( Month, (( #Year - 1900 ) * 12 ) + #Month - 1, #Day - 1 )
Simply use substrings from your original field to extract #Year, #Month and #Day. For instance, if you have a numeric like 19531231 for december 31th, 1953, you could do :
DateAdd( Month, (( SubString(Cast(DateField As Varchar(8)), 1, 4) - 1900 ) * 12 ) +
SubString(Cast(DateField As Varchar(8)), 5, 2) - 1,
SubString(Cast(DateField As Varchar(8)), 7, 2) - 1 )