How to separate this field into two columns - sql

I've got a seamingly simple problem to solve that normally would be fairly easy. I've got a field that contains a DateTime portion, as well as a trailing text portion. I now need to split this field into two discrete fields - DateTime and Varchar. Now for the little gotcha. The data has been saved with two different date formats which has resulted in the filed looking a 'lot' like this:
amendmentnote
----------------------------------------------------------------------
30/07/2010 11:39:55: Booking status change from On Option to Cancelled
5/5/2010 10:1:8 : New
as you can see, the dates are in two completely different formats. I'd like to somehow see it parsed out as:
dateofnote | note
----------------------------------------------------------------------
30/07/2010 11:39:55 | Booking status change from On Option to Cancelled
05/05/2010 10:01:08 | New
is this easily do-able??
cheers
jim

Easily? No. Do-able. Yes, if we can make some assumptions. If it is the case that the text never contains a colon, you could do:
Declare #Data Table ( Data Varchar(max) )
Insert #Data(Data) Values('30/07/2010 11:39:55: Booking status change from On Option to Cancelled')
Insert #Data(Data) Values('5/5/2010 10:1:8 : New')
Set DateFormat DMY
Select Cast(Reverse(Substring(Reverse(Data), CharIndex(':', Reverse(Data)) + 1, Len(Data))) As DateTime)
, LTrim(Reverse(Substring(Reverse(Data), 1, CharIndex(':', Reverse(Data)) - 1)))
From #Data

It's do-able, but it'll be ugly.
You can use string functions to find the third colon in the amendmentnote field, and anything to the right of the third colon will be your note.
As for the date, you should again be able to use string functions to reformat the date portion, although you'll most likely need lots of substrings to make it work.
My only concern would be if the date formats entered are MM/DD/YYYY for one entry, and DD/MM/YYYY for the other.

Based on what's provided, use:
SELECT CONVERT(DATETIME,
SUBSTRING(t.amendmentnote, 1, LEN(SUBSTRING(t.amendmentnote, 1, PATINDEX('%: %', t.amendmentnote)))-1),
103),
LTRIM(SUBSTRING(t.amendmentnote,
LEN(SUBSTRING(t.amendmentnote, 1, PATINDEX('%: %', t.amendmentnote)))+1,
LEN(t.amendmentnote)))
FROM YOUR_TABLE t
Being a DATETIME, you can use CAST/CONVERT to format it as you like - don't store "presentation" data.
Bad data is bad data - this is a mine field you'll have to navigate, isolating rows that won't match the pattern in the query & deal with appropriately.

Once in a DateTime column, they'll be in the standard DateTime format. How they're presented once queried at that point is up to you.
So, once you split your data into your DateOfNote and Note columns, you can Convert the DateOfNote to VarChar and apply a format to get what you want.
Convert(NVARCHAR, DateOfNate, 103) will get you there (I think: double check the format style there at the end).
Edit Based on your question, it looks like you wanted more help with the formatting. However, on the splitting the column, you'll need to use string functions. I'd find the index of that last colon, store it in a local variable, and then use substring to find the datetime (left of that last colon) and the note (right of last colon).

Related

SQL: What is the equivalent of "%" for date/time?

The goal is to, by default, populate all the input fields of a query with a '%' and let the user put in real values wherever they want. However, this is causing a problem for the DATE/TIME field. I get the error: Conversion failed when converting date and/or time from character string. How can I achieve the equivalent of '%' but for dates?
DECLARE #trans_date datetime = '%'
SELECT
t.lp_num,
t.trans_date
FROM ISW_LPTrans AS t
WHERE t.trans_date = #trans_date
Edit: - Removed the LIKE and replaced with = because people kept focusing too much on that and it's not the focus of this question.
This is too long for a comment. Your query doesn't make sense. LIKE is for strings and dates are not strings.
If you like, you can convert the date to a canonical string format and then use that.
However, date pickers are the more typical solution for choosing dates, and the resulting code does not use LIKE.
You cannot use LIKE keywords directly on dates. LIKE is mostly used for string values.
However you can use the CONVERT function to cast your date as varchar and then apply the LIKE keyword. For example:
CONVERT(VARCHAR(25), trans_date, 126) LIKE '2016-10-01%'
The goal is to, by default, populate all the input fields of a query
with a '%' and let the user put in real values wherever they want.
If you want that user should be allowed to enter a date then you can simply provide NULL value to your date column instead of populating it with a % value(which is absolutely vague for a date column)

Different date formats in single column in sql server

I am using SQL server. We have date column in table but some of them are stored in different format.
For e.g: We have records with format 2015-12-09 00:00:12.000 but some records are there with format as 2015/09/09 00:08:09.000 or any other valid date type.
How can I identify records with different date format from table.
I tried using isdate() function but as all date are valid there is no luck.
Can you please guide me with this.
Solution part 1
Although it is possible that this solution might not completely solve your issue, if at least you can unify your dates to look similar to each other then your position should be very much improved by placing the following at the top of your query:
SET DATEFORMAT DMY
OR
SET DATEFORMAT YMD
OR
SET DATEFORMAT MDY
Example
SELECT
[date]
FROM
[your_table]
Points of note:
M means month, D means day and Y means year.
Setting the DATEFORMAT affects both how dates appear in the result set and how dates are converted to VARCHAR and similar.
If you don't set the DATEFORMAT then running the same stored procedure on different machines/set-ups can yield differing results.
Solution part 2
You can also perform some string manipulation to replace -, /, etc. with the character of your choice.
..Put the following at the top of your query:
DECLARE #DateSeparator NVARCHAR(1) = '/'
..Use the following as part of your select statement:
REPLACE(REPLACE([date], '/', #DateSeparator), '-', #DateSeparator)
Example
SELECT
REPLACE(REPLACE(CONVERT(NVARCHAR(20), [date]), '/', #DateSeparator), '-', #DateSeparator) AS [date]
FROM
[your_table]
Points of note:
In the above example, the date separator is set to /, but change the value of #DateSeparator to the date separator of your choice.
Both solutions combined
Example
SET DATEFORMAT YMD
SELECT
REPLACE(REPLACE(CONVERT(NVARCHAR(20), [date]), '/', #DateSeparator), '-', #DateSeparator) AS [date]
FROM
[your_table]
Points of note:
Replace [your_table] with the name of your source table.
Since the dates were stored as VARCHAR instead of DATETIME (as they should have been) then there really is no way through SQL to determine it. Is the date '2016-02-01' February 1st or January 2nd? If you can't tell then how is any computer code going to figure it out?
Your best bet is to go back through the application(s) that have inserted or updated data in the table and try to figure out what they might have used. If users were just typing in data then that's unlikely to help, although maybe you can look for some consistencies - Janice always enters data MM/DD/YYYY, but Pierre always puts it in as DD/MM/YYYY, etc. That's probably your best bet in narrowing it down. Otherwise, you might look at other data in your system - if the table also has an inserted_on column for example, then maybe that and your other date would usually be within a few days of each other, etc.

SQL - How to search WHERE but ignore first two characters

I need to perform a date search but the data is a String with the format
'dd/mm/yyyy'
I want to search only for 'mm/yyyy'
For example I want all records that have '07/2014' regardless of what day?
I'm sure its something simple just can't figure it out
EDIT:
It looks like the format is MM/DD/YYY
Looks like I got this sorted just used:
RIGHT(BookedDate,5) = '/2014'
AND LEFT (BookedDate,2) = '7/'
Thanks All :)
If your string is in the format of dd/mm/yyyy always, as in 01/09/2014 you could use right:
declare #val as varchar(10)
Set #val='1/2/2014'
RIGHT(#val,7)
if you are not sure of the format but know that there is a / you could search for it:
declare #val as varchar(10)
Set #val='1/2/2014'
select right(#val,len(#val)-patindex('%/%',#val))
myfield like '%/07/2014'
Beware, since the wildcard (%) is put at the beginning of the query no indexes (if they exist) will be used. This will always be a full table scan.
If you store your date values in character based column, than jyparask's answer is good enough, but if you store it in date/time based column, then use date/time functions or intervals:
WHERE
myDateColumn >= '01/07/2014'
AND myDateColumn < '01/08/2014'
The above WHERE condition means: all values in July, 2014.
This will ensure that, because its a string, if the value is longer than expected the first three characters will always be removed.
SELECT RIGHT(field, LEN(field)-3) FROM database
This feels like a very bad idea. Most likely there is a ton of optimizations that could be done automatically for your queries by the database if you used Date instead of the String.
This is certainly going to be some kind of bottleneck if your database grows, it would have to ask and parse every single row to find out if it matches your request.

Insert only Month and Year date to SQL table

I am using MS SQLServer and trying to insert a month/year combination to a table like this:
INSERT INTO MyTable VALUES (1111, 'item_name', '9/1998')
apparently, the above command cannot work since
Conversion failed when converting date and/or time from character string.
Because 9/1998 is a bad format. I want to fix this and this column of the table will show something like:
9/1998
12/1998
(other records with month/year format)
...
Can someone help me with this?
thank you
SQL Server only supports full dates (day, month, and year) or datetimes, as you can see over on the MSDN data type list: http://msdn.microsoft.com/en-us/library/ff848733(v=sql.105).aspx
You can use a date value with a bogus day or store the value as a string, but there's no native type that just stores month/year pairs.
I see this is an old post but my recent tests confirm that storing Date or splitting the year and month to two columns (year smallint, month tinyint) results in the overall same size.
The difference will be visible when you actually need to parse the date to the filter you need (year/month).
Let me know what do you think of this solution! :)
Kind regards
You can just use "01" for the day:
INSERT INTO MyTable VALUES (1111, 'item_name', '19980901')
You can:
1) Change the column type to varchar
2) Take the supplied value and convert it to a proper format that sql server will accept before inserting, and format it back to 'M/YYYY' format when you pull the data: SELECT MONTH([myDate]) + '/' + YEAR([myDate]) ...
You may want to consider what use you will have for your data. At the moment, you're only concerned with capturing and displaying the data. However, going forward, you may need to perform date calculations on it (ie, compare the difference between two records). Because of this and also since you're about two-thirds of the way there, you might as well convert this field to a Date type. Your presentation layer can then be delegated with the task of displaying it appropriately as "MM/yyyy", a function which is available to just about any programming language or reporting platform you may be using.
if you want use date type, you should format value:
declare #a date
SELECT #a='2000-01-01'
select RIGHT( convert (varchar , #a, 103), 7) AS 'mm/yyyy'
if you want make query like SELECT * FROM...
you should use varchar instead date type.

Easy way to force DATEPART to output as fixed-length?

When I do for example DATEPART(mm, GETDATE()) I get the result of the month being "8" for August. If i did the same thing in December I would get "12". Those are two different length results.
Is there a way to get the DATEPART results to always be a fixed length? So that for example the months would show up as 08 or 12. And days would be 05 and 30.
More Details:
I'm using a derived column transformation in SSIS to take a server datestamp, and remove all the formatting (spaces, colons, dashes, etc) in order to use it as part of a Primary Key.
My forumula that currently works is below, however it results in variable lenght results which is not ideal. I would like to get all results to be the same lenght.
((DT_STR,4,1252)DATEPART("yyyy",createDate)) + ((DT_STR,2,1252)DATEPART("mm",createDate)) + ((DT_STR,2,1252)DATEPART("dd",createDate)) + ((DT_STR,2,1252)DATEPART("hh",createDate)) + ((DT_STR,2,1252)DATEPART("mi",createDate)) + ((DT_STR,2,1252)DATEPART("ss",createDate)) + ((DT_STR,2,1252)DATEPART("ms",createDate))
Input looks like this:
9/11/2008 8:50:47:300 PM
Results look like:
20089112050473
Results should look like:
20080911205047300
SELECT RIGHT(100+DATEPART(mm, GETDATE()),2)
EDIT based on new info
- to get your timestamp to a fixed string of numbers:
SELECT REPLACE(REPLACE(REPLACE(REPLACE(CONVERT(varchar(23), GETDATE(), 121),'-',''),':',''),' ',''),'.','')
The return type of DATEPART is int. The moment you ask for 05, is no longer and int but a string (char, varchar, nchar, nvarchar etc). As long as you understand the difference and you are OK with it, there are all sort of manipulations you can do to format the string as you whish, a good example being the one DJ showed. In truth though the proper place for such manipulations is on the client reporting, not on the server.
You can use CONVERT to grab a fixed-length date, for example:
SELECT CONVERT(nvarchar(30), GETDATE(), 126)
Which will show:
2006-04-18T09:58:04.570
which every variable in a fixed position.
Building on Andomar's example above:
SELECT REPLACE(REPLACE(REPLACE(REPLACE(
CONVERT(nvarchar(30), GETDATE(), 126),'-',''),'.',''),':',''),'T','')
Which will show:
20060418095804570
Caution: using a timestamp as a primary key WILL eventually bite you in the butt. Also, a primary key that is a number will be faster than a long string like this, so consider changing your algorithm to use a numeric conversion of the timestamp rather than a string.
Solution #2 Use a .NET user-defined function that wraps DateTime.ToString() so you can pass a specific format ("yyyymmddHHMMss" or whatever). Given the number of casts and replacements, it's possible this might perform just as well as straight T-SQL.