SQL date format from float (without a '1') - sql

I have been given some data where there is a 'float' column that contains a date with a 1 in the front of it. I.e the value 1171030 represents 30th October 2017.
I am stuck in attempting to convert it to a normal date, when attempting to remove the one a dot appears (i.e. .171030).
Would really appreciate some guidance.
Many thanks

Yuck! Let's try datefromparts():
select datefromparts((val - 100000) / 10000, floor(val / 100) % 100, val % 100)
Or, here is another approach:
select convert(date, right(convert(varchar(255), cast(val as int)), 6))
SQL Server is actually pretty flexible in the date formats it understands.

I'm assuming this was probably produced by a non-Y2K compliant method such as JavaScript getYear() which simply returns current year minus 1900. It's not clear to me whether this data is coming from a flat file or it is already imported into a database table.
If you treat this value as a character string:
case length(val)
when 7 then cast('20' + right(val, 6) as date)
when 6 then cast('19' + val as date)
end
If you truly have a float (or int) value:
cast(cast(cast(19000000 + #val as int) as char(8)) as date)
In this case you'll need to convert through a character value rather than going straight to date. Be careful with string conversions from float to char. If you prefer shorter then you may be able to get away with this one:
cast(str(19000000 + #val, 8) as date);
You might get errors by assuming a length of 8 but that's probably a good way to catch and prevent problems.

Related

SQL Convert & Cast Nvarchar Time to a decimal

I'm working on a legacy database and need to parse info from one database to another, parsing it into the new database is easy enough but first I need to create the query to convert and cast the following in the legacy SQL Server database:
WorkedHours(NVARCHAR(10)) is in text format 07:30
I need to convert and cast this as a decimal ie 7.5
I have searched around for the answer to this but can not find anything that has worked, so thought I would put it out there to see if any of you has any ideas.
Edit - What I should of asked is. What is causing an error converting to an int from a character with a value of 0 when trying to trying to convert and cast a time to a decimal?
DATEDIFF(
MINUTE,
0,
CAST('07:30' AS TIME)
)
/
60.0
Works up to '23:59' only
EDIT:
Based on a comment elsewhere, you have some 'bad' values.
This may find them...
SELECT
*
FROM
yourTable
WHERE
TRY_CONVERT(TIME, worked_hours) IS NULL
And as such, this is a safer version of my expression....
DATEDIFF(
MINUTE,
0,
TRY_CONVERT(TIME, worked_hours)
)
/
60.0
(Returns NULL for values that failed to parse.)
There's no reason to pull out the date/time types. Just do some simple string parsing:
cast(left(right('0' + WorkedHours, 5), 2) as int)
+ cast(right(WorkedHours, 2) as int) / 60.00
This won't have any limitations on 24 hours or anything like that. It just assumes that you've got one or two digits before a colon and two digits after.
This should work in SQL Server and an example-string "1101:56" (1101h & 56 minutes) | in general from 0h to >24h:
-- Take all hours before ":" and all Minutes (2 digits) after ":" and convert it to decimal.
select convert(decimal,left('1101:56',CHARINDEX(':','1101:56')-1)) + ( convert(decimal,right('1101:56',2))/60 );
-- with column-placeholder "time_str_from_table"
select convert(decimal,left(time_str_from_table,CHARINDEX(':',time_str_from_table)-1)) + ( convert(decimal,right(time_str_from_table,2))/60 );
If the source table have NULL-Values, than use "ISNULL" with substitution-value "0.0":
-- with column-placeholder "time_str_from_table"
select isnull( ( convert(decimal,left(time_str_from_table,CHARINDEX(':',time_str_from_table)-1)) + ( convert(decimal,right(time_str_from_table,2))/60) ), 0.0);

Convert date to number data type

I am trying to convert date to number like below, not sure which function works better.
Database used is SQL Server.
Table details
create table test
(
id varchar(255),
call_date varchar(255)
);
insert into test('26203', '14-Aug-2020');
I need output as 4405726203 -- its concatenation of date (14-Aug-2014) + id (26203)
This is too long for a comment.
SQL Server allows you to convert a datetime to a float. That would be:
select cast(dte as float)
from (values (convert(datetime, '14-Aug-2020'))) v(dte)
However, the corresponding floating point value is 44055 (https://dbfiddle.uk/?rdbms=sqlserver_2019&fiddle=d142a64db0872e7572eb4fbd6d5d5fe7). It is a bit of mystery what your intention is.
You could subtract 2, but that seems arbitrary. You could calculate the number of days since 1899-12-30. But that also seems arbitrary.
In any case, once you figure out how to convert the date to the number you want, just use concat() to combine the values.
I have found the solution:
convert(varchar,CAST(CONVERT(datetime,call_date) as bigint)) + id
Under the hood, a SQL Server DateTime is a tuple of 2 32-bit integers:
The first integer is a count of days since since the epoch, which for SQL Server is 1 January 1900
The second integer is a count of milliseconds since start of day (00:00:00.000). Except that the count ticks up in 3- or 4-milliscond increments. Microsoft only knows why that decision was made.
You can get the count of days since the epoch with
convert( int, convert( date, t.call_date ) )
[wrap that in convert(varchar, ... ) to turn it into a string]
Looks like your id is already a varchar, so you can say:
select compound_key = convert(varchar,
convert(int,
convert(date,
call_date
)
)
)
+ t.id
from test t
I would suggest padding both fields with leading zeros to a fixed length so as to avoid possible collisions (assuming you're trying to generate a key here). Signed 32-bit integer overflows a 2.1 billion-ish, so 9 digits for each field is sufficient.
This works
select concat(datediff(d, 0, cast(call_date as date)), id)
from
(values ('26203','14-Aug-2020')) v(id, call_date);
Results
4405526203

SQL Server: convert and merge separate date and time columns (both integers)

I am working on a query, where I have to fill a table's column ([Result_DateTime]) with datetime values.
The datetime based on two columns, both integer. One contains the date and the other is the time, as it is.
As you can see from the picture, it is a bit difficult to merge and convert these values to an actual datetime, because of the way they are stored. Mainly the time value causing problems.
I concluded how to convert the date column:
CONVERT(DATETIME, LEFT(20200131, 8))
but then I got stuck - what to do with the time and how to merge the two into one datetime effectively?
Using function STUFF looks nasty...
Could you help me out please? I am using SQL Server 2014
Below is one method to do it:
SELECT CAST(Convert(DATE, LEFT(DATEUPDT, 8)) AS VARCHAR(10)) +' '+CAST (TIMEUPDT/100 AS VARCHAR(4)) + ':' + CAST(TIMEUPDT%(100 * (TIMEUPDT/100)) AS VARCHAR(10))+':00'
FROM TEST_TABLE_TIME;
I think I found one solution. What I tried is to avoid using varchar conversions because of how the time column's zeros are cut off. However, I am not convinced that this is the most effective way to do so:
DECLARE #DateInt int = 20200131
DECLARE #TimeInt int = 345 -- 03:45:00
SELECT CONVERT(DATETIME, LEFT(#DateInt, 8)) +
CAST(DATEADD(second, FLOOR(#TimeInt / 100) * 3600 + FLOOR(#TimeInt / 1) % 100 * 60, 0) as datetime)
I was testing it with various time values, it is working.

cast an integer converted to varchar and appended with a string to a datetime

I can't figure out why this sql code snippet does not work:
cast(cast(b.remodelyear as varchar(5)) + '-01-01' as datetime)
Remodel year is an integer consisting of a year (ex: 2012). I cast it to varchar and append a month and a day to it and then I cast the whole thing to a datetime.
This one works:
cast(cast(Yr as varchar(5)) + '-' + cast(Mth as varchar(5)) + '-' + '01' as datetime)
Where did I go wrong?
Thanks!
Personally, I wouldn't concatenate strings for this, I'd perform some (trivial) date math:
SELECT DATEADD(year, b.remodelyear - 1, '00010101')
FROM <sometable> b
(note that I'm assuming SQL Server - read this blog post for the reasoning behind the date format. If you're using a different RDBMS this'll need to be translated).
I'm curious as to why you're casting to varchar(5), as pretty much every RDBMS I'm aware of would throw an error if it encountered a fifth digit.

Date arithmetic in SQL on DB2/ODBC

I'm building a query against a DB2 database, connecting through the IBM Client Access ODBC driver. I want to pull fields that are less than 6 days old, based on the field 'a.ofbkddt'... the problem is that this field is not a date field, but rather a DECIMAL field, formatted as YYYYMMDD.
I was able to break down the decimal field by wrapping it in a call to char(), then using substr() to pull the year, month and day fields. I then formatted this as a date, and called the days() function, which gives a number that I can perform arithmetic on.
Here's an example of the query:
select
days( current date) -
days( substr(char(a.ofbkddt),1,4) concat '-' -- YYYY-
concat substr(char(a.ofbkddt),5,2) concat '-' -- MM-
concat substr(char(a.ofbkddt),7,2) ) as difference, -- DD
a.ofbkddt as mydate
from QS36F.ASDF a
This yields the following:
difference mydate
2402 20050402
2025 20060306
...
4 20110917
3 20110918
2 20110919
1 20110920
This is what I expect to see... however when I use the same logic in the where clause of my query:
select
days( current date) -
days( substr(char(a.ofbkddt),1,4) concat '-' -- YYYY-
concat substr(char(a.ofbkddt),5,2) concat '-' -- MM-
concat substr(char(a.ofbkddt),7,2) ) as difference, -- DD
a.ofbkddt as mydate
from QS36F.ASDF a
where
(
days( current date) -
days( substr(char(a.ofbkddt),1,4) concat '-' -- YYYY-
concat substr(char(a.ofbkddt),5,2) concat '-' -- MM
concat substr(char(a.ofbkddt),7,2) ) -- DD
) < 6
I don't get any results back from my query, even though it's clear that I am getting date differences of as little as 1 day (obviously less than the 6 days that I'm requesting in the where clause).
My first thought was that the return type of days() might not be an integer, causing the comparison to fail... according to the documentation for days() found at http://publib.boulder.ibm.com/iseries/v5r2/ic2924/index.htm?info/db2/rbafzmst02.htm, it returns a bigint. I cast the difference to integer, just to be safe, but this had no effect.
You're going about this backwards. Rather than using a function on every single value in the table (so you can compare it to the date), you should pre-compute the difference in the date. It's costing you resources to run the function on every row - you'd save a lot if you could just do it against CURRENT_DATE (it'd maybe save you even more if you could do it in your application code, but I realize this might not be possible). Your dates are in a sortable format, after all.
The query looks like so:
SELECT ofbkddt as myDate
FROM QS36F.ASDF
WHERE myDate > ((int(substr(char(current_date - 6 days, ISO), 1, 4)) * 10000) +
(int(substr(char(current_date - 6 days, ISO), 6, 2)) * 100) +
(int(substr(char(current_date - 6 days, ISO), 9, 2))))
Which, when run against your sample datatable, yields the following:
myDate
=============
20110917
20110918
20110919
20110920
You might also want to look into creating a calendar table, and add these dates as one of the columns.
What if you try a common table expression?
WITH A AS
(
select
days( current date) -
days( substr(char(a.ofbkddt),1,4) concat '-' -- YYYY-
concat substr(char(a.ofbkddt),5,2) concat '-' -- MM-
concat substr(char(a.ofbkddt),7,2) ) as difference, -- DD
a.ofbkddt as mydate
from QS36F.ASDF a
)
SELECT
*
FROM
a
WHERE
difference < 6
Does your data have some nulls in a.ofbkddt? Maybe this is causing some funny behaviour in how db2 is evaluating the less than operation.