I have an SQL DateKey that looks like this
YYYYMMDD
This was created using
Convert(varchar,[ModifiedOn],112))
However I want this field in a view to display the normal dateformat in the UK as DD-MM-YYYY
how can I do that.
Thank you.
Just try CONVERT(VARCHAR(10),CAST(YourStringDate AS DATE),105)
As the date-value YYYYMMDD seems to be a string in the so called unseparated format (and not a BIGINT), SQL-Server will cast this string to DATE implicitly. CONVERT together with 105 will format this the way you want it.
Starting with SQL Server 2012 there is FORMAT(). You might use this:
SELECT FORMAT(CAST(YourStringDate AS DATE),'dd-MM-yyyy')
One method dispenses with the date stuff and just uses string arithmetic:
select (right(ModifiedOn, 2) + '-' +
substring(ModifiedOn, 3, 2) + '-' +
left(ModifiedOn, 4)
) as mmddyyyy
One approach is to add a date table to your database.
Date tables can provide a handy selection of pre-calculated formats, for you to switch between.
They are also useful aggregation targets (GROUP BY DATENAME(QUARTER, CAST(DateKey AS DATE)) Vs GROUP BY DimDate.[Quater]).
-- Basic date table.
CREATE TABLE DimDate
(
DateKey INT PRIMARY KEY,
[Date] DATE NOT NULL,
[Year] INT NOT NULL,
[Quater] VARCHAR(2) NOT NULL,
[DD_MM_YYYY] VARCHAR(10) NOT NULL,
)
;
Contains:
DateKey [Date] [Year] [Quater] [DD_MM_YYYY]
--------------------------------------------------------
20160101 2016-01-01 2016 Q1 01-01-2016
20160102 2016-01-02 2016 Q1 02-01-2016
...
20161231 2016-12-31 2016 Q4 31-12-2016
There is an argument against formatting within the database. Proponants will tell you that formatting is a cosmetic operation, best performed in the presentation layer. Your database, they say, should store only the cold hard facts. Personally I'm not so sure. I agree SQL isn't the best langaue to use for formatting, but sometimes it is the only language in play.
Related
Select v.VendorCode VendorCode, V.VendorName
where
vi.Vendor_ID= 154
and
vi.Company_ID= (Select CompanyID from Company where CompanyID= '2')
AND
( Cast(vi.InvoiceDate as date) between Cast('3/1/2011' as date)
AND cast('3/29/2018' as date)
)
when I include the date part.. it doesn't return result. InvoiceDate is saved as varchar in table and is saving dates like 1/22/2019.
I cannot change the type becuase it's the legacy database and has to be changed in thousand places.
You may not be able to change the data in the database, but you can at least get in the habit of using proper date formats for your queries.
First, use convert with format 101 for the conversion. Use try_convert() if anyone got the date wrong.
Second, use 'YYYYMMDD' or 'YYYY-MM-DD' for date constants:
try_convert(date, v.InvoiceDate, 101) between '20110301' and '20180329'
Finally, you can add a computed column, so you can start to migrate to better code:
alter table v add InvoiceDate_Date as (try_convert(date, vi.InvoiceDate, 101));
Then you can write the logic as:
InvoiceDate_date between '20110301' and '20180329'
To debug, try to see what the DBMS sees when filtering by date:
Select
v.VendorCode
, v.VendorName
, cast(vi.InvoiceDate as date) as InvoiceDate
, cast('3/1/2011' as date) as FromDate
, cast('3/29/2018' as date) as ToDate
from ...
where
vi.Vendor_ID = 154
and vi.Company_ID= (Select CompanyID from Company where CompanyID= '2')
I am trying to execute a regular expression in SQL Server to match a MM/YY formatted VARCHAR string.
I have tried
WHERE ExpiryDate LIKE '[0-9][0-9]/[0-9][0-9]'
which allows incorrect dates like 30/18.
I also tried
WHERE ExpiryDate LIKE '0[1-9]|1[012]/[0-3][0-9]'
But SQL Server does not accept pipe separated as an OR operator.
I need the month to match 01 - 12
I can do
WHERE ExpiryDate LIKE '0[1-9]/[0-9][0-9]'
OR ExpiryDate LIKE '10/[0-9][0-9]'
OR ExpiryDate LIKE '11/[0-9][0-9]'
OR ExpiryDate LIKE '12/[0-9][0-9]'
but I would prefer it to be within the regular expression.
Thanks in advance for any help.
If 2012+, you could use try_convert() to convert the expiration string into a date. Try_Convert() will return a NULL value if the conversion fails.
Example
Declare #YourTable table (ID int, ExpiryDate varchar(25))
Insert Into #YourTable values
(1,'09/17')
,(2,'30/17')
Select *
From #YourTable
Where try_convert(date,replace(ExpiryDate,'/','/01/')) >= '2017-09-01'
-- Where try_convert(date,replace(ExpiryDate,'/','/01/')) is null
Returns
ID ExpiryDate
1 09/17
If you need to convalidate dates, you could try something like this:
SET DATEFORMAT dmy
;WITH A AS (SELECT '18/12' AS EXPDATE UNION ALL SELECT '10/17' UNION ALL SELECT 'x2/16' )
SELECT *, ISDATE('01/'+EXPDATE) AS CHK FROM A
Output:
EXPDATE CHK
18/12 0
10/17 1
x2/16 0
date LIKE '0[1-9]/[0-9][0-9]' OR
date LIKE '1[0-2]/[0-9][0-9]'
Is much shorter. But without | it is hard to make variants... Notice, that LIKE takes not regexes, but wildcards.
Don't forget, that '[1-9]/[0-9][0-9]' can also happen. And other variants, with inner spaces and so on. If you are not absolutely sure in month format used, and don't depend on high speed, use #JohnCampeletti variant.
I have date formats that are as follows:
Date_str
19-12-2007
31-7-2009
3-1-2010
31-11-2009
etc.
I can't do the following:
CONCAT(RIGHT(Date_str,4),SUBSTRING(Date_str,3,3),LEFT(2))
because as you can see above, the dates are not the same length. Is there a way in SQL Server to extract the date as datetime/date?
I also tried
Convert(datetime, Date_str)
but it just threw an error:
The conversion of a varchar data type to a datetime data type resulted
in an out-of-range value.
If 2012+, I would use Try_Convert(). This will return bogus dates as NULL.
Example
Declare #YourTable Table ([Date_str] varchar(50))
Insert Into #YourTable Values
('19-12-2007')
,('31-7-2009')
,('3-1-2010')
,('31-11-2009')
Select *
,try_convert(date,Date_Str,105)
from #YourTable
Returns
Date_str (No column name)
19-12-2007 2007-12-19
31-7-2009 2009-07-31
3-1-2010 2010-01-03
31-11-2009 NULL -- Notice 11/31 is NOT a date
See https://learn.microsoft.com/en-us/sql/t-sql/functions/cast-and-convert-transact-sql for date formats
You probably need
CONVERT(DateTime, Date_str, 105)
As I mentioned in the comments, the only realistic solution is to convert that string into a proper date-typed column. The current format doesn't allow date sorting, or search for a range of dates, eg to find entries in the last week, or between one date and the other.
Parsing with CONVERT or TRY_PARSE means that no indexes can be used to speed up queries. Each time :
WHERE CONVERT(Date, Date_str, 105) > '20170101'
is used, the server will have to scan the entire table to convert the data, then filter the rows.
If you can't change the type of the field itself, you can create a persisted computed column that returns the value as a date and add indexes to it. You'll be able to use that column for indexed querying:
alter table SomeTable add date2 as TRY_convert(Actual_Date,date_str,105) PERSISTED
create index IX_SomeTable_ActualDate on SomeTable (Actual_Date)
This will allow you to perform sorting without tricks:
SELECT *
FROM SomeTable
ORDER BY Actual_Date
Or run range queries that take advantage of the IX_SomeTable_ActualDate index:
SELECT *
FROM SomeTable
Where Actual_Date Between DATEADD(d,-7,GETDATE()) AND GETDATE()
If you have 1000 rows, you could get 1000 times better performance.
Existing applications won't even notice the change. Newer queries and applications will be able to take advantage of indexing and sorting
I had a similar problem: my column (<my_date_field>) had date values in the form of
2021-01
2021-02
2021-10
2021-12
and so on, with data type of nvarchar(4000), and I always ran into the Conversion failed when converting date and/or time from character string. error (when trying e.g. CAST(<my_date_field> AS DATE) or CAST(CAST(<my_date_field> AS VARCHAR(7)) AS DATE) etc.)
I was able to convert them to date with the following code:
SELECT
CONVERT(date, <my_date_field> + '-01') AS first_day_of_month
FROM my_table
which resulted in
2021-08-01
2021-07-01
2021-06-01
2021-05-01
I am creating a table of random dates with varchar(200) data type and I am unable to generate my query of getting displayed date where year > 2000
ex:
12/03/2017
12/02/1998
12/11/2002
First, you should not be storing dates as strings. It is a bad idea to store fields in the wrong type.
Second, if you do have to store dates as strings (which is occasionally necessary), then use the ISO standard formats: YYYY-MM-DD or YYYYMMDD.
For the format that you are using, you can extract the last four characters:
select right(DateWronglyStoredInStringColumn, 4) as yyyy
You should be storing your dates as a date or datetime2 or datetime datatype in sql server.
For sql server versions prior to sql server 2012, try just using convert():
For dates where the day is first, use set dateformatdmy;
set dateformat dmy;
select
year(convert(date,randomDate)) as [Year]
, randomDate
from t
where year(convert(date,randomDate)) > 2000;
For sql server 2012+, you could use try_convert():
set dateformat dmy;
select
year(try_convert(date,randomDate)) as [Year]
, randomDate
from t
where year(try_convert(date,randomDate)) > 2000;
rextester demo: http://rextester.com/DXVR82331
create table a ( date varchar(200) );
insert into a values
('13-09-2017')
,('12-12-1987')
,('27-01-2037')
,('22-04-1877')
,('02-11-1987')
,('16-08-1974');
set dateformat dmy;
select convert(date,a.[date]) as date
from a
where year(convert(date,a.[date])) > 2000;
returns:
+---------------------+
| date |
+---------------------+
| 13.09.2017 00:00:00 |
| 27.01.2037 00:00:00 |
+---------------------+
Try
select date
from a where convert(char(4),date,121) > '2000'
But be careful when you sort or order the year as You use varchar (text).
Might want to convert the year to an integer for that purpose.
I have four columns namely-
1. C_Date in YYYYMMDD format (varchar(255)) Eg. 20161231
2. C_Time in 4-digit Military format (varchar(255)) Eg. 2143
3. E_Date in YYYYMMDD format (varchar(255)) Eg. 20161230
4. E_Time in 4-digit Military format (varchar(255)) Eg. 1600
I want to Calculate the time between E event and C event. How can i perform this computation with a select statement?
Pretty simple to create a date type from the component values:
with data as (select '20161231' as c_date, '2143' as c_time)
select
convert(
datetime,
stuff(stuff(stuff(c_date + ' ' + c_time, 12, 0, ':'), 7, 0, '-'), 5, 0, '-'),
120
) as c_datetime
from data;
Use datediff() to calculate the time difference. You didn't specify how you wanted the output to look so I won't attempt a guess. There should be a hundred other questions out there with information relevant to your question though.
Also note that I did not append ':00' to the string to represent seconds. It seems to work though I couldn't track down an official document to confirm that. So to be safe you may want to tack that on as well. Arguably there could be a more universal format like ISO 8601 that would be a "better" solution. You get the idea though.
A small matter to convert your strings into a datetime. Then we use DateDiff() to calculate the differance between the two dates.
Declare #YourTable table (C_Date varchar(255),C_Time varchar(255),E_Date varchar(255),E_Time varchar(255))
Insert Into #YourTable values
('20161231','2143','20161230','1600')
;with cte as (
Select *
,CDT = try_convert(DateTime,C_Date+' '+stuff(C_Time,3,0,':'))
,EDT = try_convert(DateTime,E_Date+' '+stuff(E_Time,3,0,':'))
from #YourTable
)
Select CDT
,EDT
,Duration = concat(DateDiff(DD,EDT,CDT),' ',Format(DateAdd(Second,DateDiff(SECOND,EDT,CDT),'1899-12-31'),'HH:mm:ss'))
,AsSeconds = DateDiff(SECOND,EDT,CDT)
,AsMinutes = DateDiff(MINUTE,EDT,CDT)
From cte
Returns
CDT EDT Duration AsSeconds AsMinutes
2016-12-31 21:43:00 2016-12-30 16:00:00 1 05:43:00 106980 1783