I'm looking to convert a users input that will be a NVARCHAR to a UK date
The user's input will always be a maximum of 6 digits.
For example:
151119 (DDMMYY) --> 15NOV19
120119 (DDMMYY) --> 12JAN19
You need a valid DATE or DATETIME / DATETIME2 value first. You can get this value using this SELECT query with CONVERT:
SELECT CONVERT(DATE,
SUBSTRING('151119', 3, 2) + '-'
+ SUBSTRING('151119', 1, 2) + '-'
+ SUBSTRING('151119', 5, 2)
, 10);
Now you have two possibilities to get the date in the expected format (DDMMMYY).
1 - solution using DATENAME:
-- set the date value (from custom date value).
DECLARE #dDateValue AS DATE = CONVERT(DATE,
SUBSTRING('150419', 3, 2) + '-'
+ SUBSTRING('150419', 1, 2) + '-'
+ SUBSTRING('150419', 5, 2)
, 10);
-- format the date value to the expected format.
SELECT DATENAME(DD, #dDateValue) +
UPPER(LEFT(DATENAME(MM, #dDateValue), 3)) +
RIGHT(DATENAME(YY, #dDateValue), 2);
2 - solution using CONVERT:
-- set the date value (from custom date value).
DECLARE #dDateValue AS DATE = CONVERT(DATE,
SUBSTRING('150419', 3, 2) + '-'
+ SUBSTRING('150419', 1, 2) + '-'
+ SUBSTRING('150419', 5, 2)
, 10);
-- format the date value to the expected format.
SELECT UPPER(REPLACE(CONVERT(VARCHAR, #dDateValue, 6), ' ', ''));
demo on dbfiddle.uk
Note: I recommend to store the date values on columns with DATE or DATETIME data type. You can format the date value on your application or using format functions on SQL-Server directly.
You need to alter the string into something that looks even little like a normal date format, then you can use convert:
declare #textDate nvarchar(6) = '120119';
select #textDate
, stuff(stuff(#textDate, 3,0,'/'), 6,0,'/')
, convert(date, stuff(stuff(#textDate, 3,0,'/'), 6,0,'/'), 3);
Gives:120119,12/01/19,2019-01-12
As that last one is a valid date datatype, you can now use Format().
Though obviously 2 digit years are a bad idea in the first place.
Forgot to say, the 3 is for UK 2 digit format(dd/mm/yy), and you can see the other choices here.
I highly recommend to work with date values on columns AS DATE or DATETIME type. This is a simple implementation for your need :
SQL Fiddle
MS SQL Server 2017 Schema Setup:
create table test (mydate nvarchar(6))
insert into test (mydate)values('151119')
insert into test (mydate)values('120119')
Query 1:
select FORMAT(CONVERT(DATE, dates), 'dd/MM/yyyy ') from (select left(mydate,2)
+
CASE SUBSTRING(mydate, 3, 2)
WHEN '01' THEN 'JAN'
WHEN '02' THEN 'FEB'
WHEN '03' THEN 'MAR'
WHEN '04' THEN 'APR'
WHEN '05' THEN 'MAY'
WHEN '06' THEN 'JUN'
WHEN '07' THEN 'JUL'
WHEN '08' THEN 'AUG'
WHEN '09' THEN 'SEP'
WHEN '10' THEN 'OCT'
WHEN '11' THEN 'NOV'
WHEN '12' THEN 'DEC'
ELSE 'error'
END
+ right(mydate,2) AS 'dates'
from test ) AS T
Results:
| |
|-------------|
| 15/11/2019 |
| 12/01/2019 |
Related
I have got two columns of nvarchar.
Sample data is:
column1='20180402', column2='134259'
My goal is to create a datetime type column by combining these two columns.
Like this: '2018-04-02 13:42:59.000'
How can I do that ?
Please, help me ?
You can either convert both strings to a datetime value and add them together to get your combined datetime or combine the strings and convert the result.
Note the time will need two : characters added to correctly parse:
select cast(d as datetime) + cast(stuff(stuff(t,5,0,':'),3,0,':') as datetime) as dt1
,cast(d + ' ' + stuff(stuff(t,5,0,':'),3,0,':') as datetime) as dt2
from (values('20180402','134259')) as v(d,t);
Output
+-------------------------+-------------------------+
| dt1 | dt2 |
+-------------------------+-------------------------+
| 2018-04-02 13:42:59.000 | 2018-04-02 13:42:59.000 |
+-------------------------+-------------------------+
You can use DATETIMEFROMPARTS:
SELECT DATETIMEFROMPARTS(
SUBSTRING(column1, 1, 4),
SUBSTRING(column1, 5, 2),
SUBSTRING(column1, 7, 2),
SUBSTRING(column2, 1, 2),
SUBSTRING(column2, 3, 2),
SUBSTRING(column2, 5, 2),
0
)
FROM (VALUES
('20180402', '134259')
) v(column1, column2)
declare #d varchar(50)='20180402',
#t varchar(50)='134259'
select convert(varchar(50),convert(date,#d)) + ' '+ convert(varchar(50),dateadd(hour, (#T / 10000) % 100,
dateadd(minute, (#T / 100) % 100,
dateadd(second, (#T / 1) % 100,
cast('00:00:00' as time(3))))) )
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/
Currently developing a package that passes an expression from a previous date to a filename. The current code I have is the following as a string variable:
(DT_WSTR,20)DATEPART("YYYY",Dateadd("DD",-1,dateadd("MM",datediff("MM",
(DT_DATE) "1900-01-01",getdate())-2, (DT_DATE) "1900-01-01")))
+ RIGHT("0"+(DT_WSTR,20)DATEPART("MM",Dateadd("DD",-1,dateadd("MM",datediff("MM", (DT_DATE) "1900-01-01",getdate())-5, (DT_DATE) "1900-01-01"))),2)
+ "01"
This currently produces the output of:
20171101
This is currently incorrect because I'd like the date to be from the previous year:
20161101
Here's the forumula I'd like:
Return the 1st day of the month that is 7 months in the past from today's date.
Example: 5/2/2017 would return 11/1/2017; 6/21/2017 would return 12/1/2016; 7/10/2017 would return 1/1/2017; etc.
Is this possible to do via a variable in SSIS?
Your expression can be modified (and simplified) to this
(DT_WSTR, 8)( ( YEAR( DATEADD( "MM", -7, GETDATE() ) ) * 10000 ) + ( MONTH( DATEADD("MM", -7, GETDATE() ) ) * 100 ) + 1 )
subtract 7 months from current date
multiply resulting year by 10000
subtract 7 months from current date
multiply resulting month by 100
add year-value, month-value and 1 (first day)
convert to string
Credit to #Rangani in Yesterday's date in SSIS package setting in variable through expression for "multiply and add instead of string concat" trick
SELECT LEFT(CONVERT(VARCHAR, DATEADD("MM", -6, '2017-05-02'), 112), 6) + '01'
SELECT LEFT(CONVERT(VARCHAR, DATEADD("MM", -6, '2017-06-21'), 112), 6) + '01'
SELECT LEFT(CONVERT(VARCHAR, DATEADD("MM", -6, '2017-07-10'), 112), 6) + '01'
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 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".