I'm working trying to convert a string data type to a date that does not contain 0's in the string of the month and day part and need to convert it into a date format yyyy-MM-dd, anything that is a single digit will come without a zero
For example, the dates come in as
162022 it should be (01-06-2022)
or
762022 it should be (07-06-2022)
or
1262022 it should be (12-06-2022)
How can I get the proper formatting to get it into a date data type using a Derived Column?
Try using the following expression:
LEN([StringColumn]) == 6 ? "0" + LEFT([StringColumn],1) + "-0" + SUBSTRING([StringColumn],2,1) + "-" + RIGHT([StringColumn],4) :
LEN([StringColumn]) == 8 ? LEFT([StringColumn],2) + "-" + SUBSTRING([StringColumn],3,2) + "-" + RIGHT([StringColumn],4) :
LEN([StringColumn]) == 7 ?
(DT_I4)SUBSTRING([StringColumn],2,2) > 12 ? LEFT([StringColumn],2) + "-0" + SUBSTRING([StringColumn],3,1) + "-" + RIGHT([StringColumn],4) : "0" + LEFT([StringColumn],1) + "-" + SUBSTRING([StringColumn],2,2) + "-" + RIGHT([StringColumn],4) : [StringColumn]
This expression logic can be summarized in the following table
Input length
Date Format
Example
How to convert into date
6
dmyyyy
162021
add zero before the first and second digits
7
dmmyyyy or ddmyyyy
1262021 or 2122021
check if the second and third digits are greater than 12 then consider that the first two digits are for the day part else consider only the first digit for the day
8
ddmmyyyy
01062021
do nothing
< 6 or > 8
?
?
do nothing
This expression is valid except with values like 1112021 where it is not easy to predict if the day part is 11 or the month part us 11.
You could try a brute-force approach, but as the sample below illustrates, there can be more than 1 possible date.
It is a risky format, and extreme caution is required.
Example
Declare #YourTable Table ([SomeCol] int) Insert Into #YourTable Values
(162022)
,(7182022)
,(1262022)
,(12182022)
Set DateFormat MDY
Select SomeCol
,AsDate
,Cnt = sum(1) over (partition by [SomeCol])
From #YourTable A
Cross Apply ( values ( stuff(reverse(SomeCol),5,0,'-') ) ) B(rStr)
Cross Apply ( values ( stuff(rStr,7,0,'-') )
,( stuff(rStr,8,0,'-') )
,( stuff(rStr,9,0,'-') )
) C(tStr)
Cross Apply ( values ( try_convert(date,reverse(tStr)) ) ) D(AsDate)
Where AsDate is not null
Results
SomeCol AsDate Cnt
162022 2022-01-06 1
1262022 2022-01-26 2 <<< Two valid dates
1262022 2022-12-06 2 <<< Two valid dates
7182022 2022-07-18 1
12182022 2022-12-18 1
Related
trying to query a table that stores prices but need a way to append + if number is >1 and - if <1 and append up to 8 zeros after the + or - sign , and round to 2 decimal places so if table contains
Current table: prices
1000.3334
Expected return: prices
+00001000.33
Tried the following query but it does not round to 2 decimal places and does not add the + or - sign
SELECT RIGHT('00000000'+ CONVERT(VARCHAR,prices),11) AS NUM FROM SALES;
While I agree with others, yuck, this belongs in your front end / presentation layer:
SELECT CASE WHEN prices < 0 THEN '-' ELSE '+' END
+ RIGHT(CONCAT(REPLICATE('0',9),
ABS(CONVERT(decimal(11,2),prices))), 11)
FROM dbo.sales;
Working example in this fiddle.
I have the following code; the only issue with it is that sometimes it generates a digit alphanumeric code.
I am trying to modify it such that it always returns a 6 digit code. Any thoughts on how to tweak this?
I have another procedure the purges duplicates and it re-runs, so that is not an issue.
SET #HashCode = NULL
SELECT
#HashCode = ISNULL(#HashCode, '') + SUBSTRING('23456789ABCDEFGHJKLMNPQRSTUVWXYZ', (ABS(CHECKSUM(NEWID())) % 36) + 1, 1)
FROM
[master]..[spt_values] AS [spt_values] WITH (NOLOCK)
WHERE
[spt_values].[type] = 'P'
AND [spt_values].[number] < 6
A very simple way of achieving this is selecting the first 6 LEFT characters in the string generated by the NEWID() function:
SELECT LEFT(NEWID(), 6)
Examples:
4DF32A
DC70D5
8793B2
3D8416
EE2838
Note, because the NEWID() function generates a unique identifier (GUID), consisting of hexadecimal characters (A-F & 0-9), there is a chance the output will consist of only numbers or only letters; which may or may not fit your purpose if you require a strict alphanumeric value.
Examples:
946983
831814
DDFDBB
You can use it like this:
SET #HashCode = NULL
SELECT
#HashCode = LEFT(NEWID(), 6)
I have data harvested from a binary file that has been encoded as a SQL column with type varchar(4). This is not changeable. The 4 bytes used to create this varchar need to be interpreted sometimes as an int value (big endian). It would be nice if we could do this entirely inside SQL.
Printing the values in this varchar(4) column is not helpful as most of the bytes get interpreted as unprintable control characters.
I can't figure out how CAST or CONVERT can help since they seem to be tailored to converting a varchar like "0054" to int 54. Instead, I need the underlying bits to be interpreted as an int (big endian)--not the varchar characters as an int.
For example, one record prints this column as no visible characters, but STRING_ESCAPE(#value,'json')
will display
\u0000\u0000\u0000\u0007
This needs to be interpreted somehow to be the int 7
Here's a few more examples of what STRING_ESCAPE returns and what the int value should be:
\u0000\u0000\u0000\b ==> 8
\u0000\u0000\u0000\t ==> 9
\u0000\u0000\u0000\n ==> 10
\u0000\u0000\u0000\u000b ==> 11
\u0000\u0000\u0000\f ==> 12
\u0000\u0000\u0000\r ==> 13
\u0000\u0000\u0000\u000e ==> 14
\u0000\u0000\u0000\u000f ==> 15
\u0000\u0000\u0000\u0010 ==> 16
Thanks for your brain!
So, here is a table of sample data. The first row represents your main example. But you don't have any examples where any one of the first 3 characters is not character 0. So I threw in another row where this is the case.
declare #values table (value char(4))
insert #values values
(char(0) + char(0) + char(0) + char(7)),
(char(13) + char(9) + char(14) + char(8));
In the query below, I isolate each character using substring. Then I call ascii to retrieve the character code. What is not clear, however, is how you would take those integer values and combine them. I give 3 possibilities. 'Option1' concatenates them. 'Option2' sums them together. 'Option3' concatenates them like option1, but pads them first so that there is a leading '0' if it is only one digit long.
select escapedVal = string_escape(value,'json'),
ap.*,
option1 = convert(int,concat(pos1, pos2, pos3, pos4)),
option2 = pos1 + pos2 + pos3 + pos4,
option3 = convert(int,
right('00' + convert(varchar(2),pos1),2) +
right('00' + convert(varchar(2),pos2),2) +
right('00' + convert(varchar(2),pos3),2) +
right('00' + convert(varchar(2),pos4),2)
)
from #values v
cross apply (select
pos1 = ascii(substring(value,1,1)),
pos2 = ascii(substring(value,2,1)),
pos3 = ascii(substring(value,3,1)),
pos4 = ascii(substring(value,4,1))
) ap;
This produces:
escapedVal
pos1
pos2
pos3
pos4
option1
option2
option3
\u0000\u0000\u0000\u0007
0
0
0
7
7
7
7
\r\t\u000e\b
13
9
14
8
139148
44
13091408
CAST(CAST(#value as BINARY(4)) as INT)
The part I was missing is specifying the size of binary as 4. Without the size, it always casts to 0!
I am using SQL Server 2016 and I'm trying to convert military time to standard time. The military time is a 4 digit integer and I'm trying to get the standard time format (00:00 am/pm).
I ran a simple CASE statement that made it standard but without ':' and 'am/pm'.
CASE
WHEN SA_BEGTIME between 0 and 1259 then SA_BEGTIME
WHEN SA_BEGTIME between 1300 and 2400 then SA_BEGTIME - 1200
ELSE ''
END as Time
Results
How do I convert it so that it is in the right format: '00:00 am/pm'
Thank you!
You can split it into parts with integer division and modulo, cast it to a VARCHAR and then you can convert it to a TIME:
declare #x int = 109
select cast(cast(#x / 100 as varchar(2)) + ':' + cast(#x % 100 as varchar(2)) as time)
Or you can use the new TIMEFROMPARTS() function (SQL Server 2012+):
declare #x int = 109
select TIMEFROMPARTS(#x / 100,#x % 100, 0, 0, 0)
You can then format it however you'd like.
Assuming your data is stored as an integer, and also assuming there is not invalid time stored (i.e. values above 2400 or below 0) you can use the following:
declare #TheTime int = 900
select right(convert(varchar(20),
cast(stuff(right('0000' + convert(varchar(4),#TheTime),4),3,0,':')
as datetime),100),7)
-------
9:00AM
Sorry for the density of the solution. This is what I did:
Convert #TheTime to varchar(4)
Add a string of zeros at the front
Take the rightmost 4 characters from this new string
Stuff a colon sign in the middle of this new string
Cast the string as datetime
Convert back to string using 100 as the style indicator to get AM/PM
Get the right most 7 characters of the string.
I am sure there are more elegant ways, but this one works for me quite well.
I'm using the solution that #BaconBits provided but I had to make a tweak because 2400 was a valid representation but it failed with that code. Here's the tweaked solution:
declare #x int = 2400
select TIMEFROMPARTS((#x / 100) % 24,#x % 100, 0, 0, 0)
I needed to convert a datetime field where the time was military to just the time in AM/PM format. This worked beautifully.
Left(convert(varchar(20), cast(MyDateField as time),100),7)
You can use convert to get n appropriate presentation of time.
declare #mt varchar(4) = '1500'
select convert(varchar, cast(left(#mt, 2) + ':' + right(#mt, 2) as time), 0)
I have a SQL Server database.
One field has values which are like
ID VALUE
1 NEGATIF
2 11.4
3 0.2
4 A RH(+)
5 -----
6 >>>>>
7 5.6<
8 -13.9
I want to CONVERT VALUE field to decimal, of course convert-able fields.
What kind of SQL statement can do this?
How can I understand which value is raising error while converting?
PS: I think this can solve WHERE VALUE LIKE '[a-z]' but how can I add more filter like [-+ ()] ?
Plain ISNUMERIC is rubbish
Empty string, +, - and . are all valid
So is +. etc
1e-3 is valid for float but not decimal (unless you CAST to float then to decimal)
For a particularly cryptic but failsafe solution, append e0 or .0e0 then use ISNUMERIC
SELECT
ISNUMERIC(MyCOl + 'e0') --decimal check,
ISNUMERIC(MyCOl + '.0e0') --integer check
So
SELECT
ID, VALUE,
CAST(
CASE WHEN ISNUMERIC(VALUE + 'e0') = 1 THEN VALUE ELSE NULL END
AS decimal(38, 10)
) AS ConvertedVALUE
FROM
Mytable