Standardizing dates in SQL. Arithmetic overflow - sql-server-2005

I have a string field dob which has birthdates in various formats e.g.
dob
July 1, 1945
1967-1-7
13 May 1956
8 May 1947
27 September 1953
1952-3-25
I have attempted to use MS SQL 2005 to create a standardized date field
select convert(datetime,dob,103)
from myTable
I get an arithmetic overflow which appears to be associated with the last value, presumably because it is trying to convert the 25 to a month when it is a day
I have tried
setting the language to british and various other styles without success
Any suggestions?

Why would you attempt to store it in a given format? Can you not just store it as a datetime type? The biggest advantage to storing it in a locale independent is that you can offload the presentation logic to the UI where it belongs. Plus, you can avoid messy situations where you have a DOB of 3-4-5 (2003 April 5th, March 4th 2005, 3rd April 2005).
Conversion to a datetime works just fine for me (US locale).
; with myTable (dob)as
(
select 'July 1, 1945'
UNION ALL SELECT '1967-1-7'
UNION ALL SELECT '13 May 1956'
UNION ALL SELECT '8 may 1947'
UNION ALL SELECT '27 september 1953'
UNION ALL SELECT '1952-3-25'
)
SELECT
cast(T.dob AS datetime) AS real_datetime
, T.dob
FROM
myTable T
Results
real_datetime dob
1945-07-01 00:00:00.000 July 1, 1945
1967-01-07 00:00:00.000 1967-1-7
1956-05-13 00:00:00.000 13 May 1956
1947-05-08 00:00:00.000 8 may 1947
1953-09-27 00:00:00.000 27 september 1953
1952-03-25 00:00:00.000 1952-3-25

Related

Oracle - How to convert Date represented by NUMBER(6,0) format

I've got data from our third party partner and every date column is coded in this NUMBER(6,0) format:
118346
118347
118348
118351
119013
119035
119049
119051
118339
118353
119019
119028
119029
119031
None of the last 3 digits are more than 365, so I reckon 118339 must mean 2018 + 339 days, which is December 5, 2018: '2018-12-05'. I've never encountered this kind of format before, so I'm a bit helpless how to handle it. Is this some standardized format? Can I use some built-in convert function or should I just manually cut and convert it using some arithmetics?
I would like to sort my rows grouping by weeks, so maybe I shouldn't even convert it, but for some reason I feel converting to a date type would be more elegant. Which approach is the better?
EDIT: I've just checked my excel version of the data, and this format is in fact working as I've imagined. So the question stands.
This seems to be Excel's 1900-based internal representation of dates. Assuming your interpretation is right, you can convert to a normal date with a bit of manipulation:
-- CTE for sample values
with your_table (num) as (
select *
from table(sys.odcinumberlist(118339, 118346, 118347, 118348, 118351, 119013, 119035,
119049, 119051, 118339, 118353, 119019, 119028, 119029, 119031))
)
-- actual query
select num,
date '1899-12-31'
+ floor(num/1000) * interval '1' year
+ mod(num, 1000) * interval '1' day as converted
from your_table;
NUM CONVERTED
---------- ----------
118339 2018-12-05
118346 2018-12-12
118347 2018-12-13
118348 2018-12-14
118351 2018-12-17
119013 2019-01-13
119035 2019-02-04
119049 2019-02-18
119051 2019-02-20
118339 2018-12-05
118353 2018-12-19
119019 2019-01-19
119028 2019-01-28
119029 2019-01-29
119031 2019-01-31
This treats the first three digits - obtained with floor(num/1000) - as the number of years, offset from 1900. Those are multiplied by a single year interval value, to give 118 or 199 years. Then it treats the last three digits - from mod(num, 1000) - as the number of days into that year, by multiplying by a single day interval. Both are then added to the fixed date 1899-12-31. (You could use 1900-01-01 instead but then you have to subtract a day at the end...)

SQL DatePart Week, year to reflect fiscal year

I currently have a report that uses DATEPART to return the week a 'car' was returned. However, the business I work for fiscal year starts first Sunday of the year (this instance commencing 03/01/2016 would be week 1). However, using SQL 'DATEPART wk' would return this date is week 2:
Current outcome using DATEPART (wk, year etc):
CarTitle ReturnDate Year Week
Car 1 30/12/2015 2015 53
Car 2 02/01/2016 2016 1
Car 3 03/01/2016 2016 2
Car 4 05/01/2016 2016 2
Car 5 10/01/2016 2016 3
Car 6 17/01/2016 2016 4
Example of expected outcome:
CarTitle ReturnDate Year Week
Car 1 30/12/2015 2015 53
Car 2 02/01/2016 2015 53
Car 3 03/01/2016 2016 1
Car 4 05/01/2016 2016 1
Car 5 10/01/2016 2016 2
Car 6 17/01/2016 2016 3
I can calculate this with the following SQL:
SELECT
CarTitle,
DATEPART(ISO_WEEK, DATEADD(day, 1, ReturnDate))
FROM
dbo.My_Table
However, this depends on your localization settings (which are probably different from mine given how you express dates) and if you use this code throughout your system and then the business decides to change it's method for calculating weeks then you could end up with a big refactorization headache.
I prefer to use a Calendar table for this sort of thing:
CREATE TABLE dbo.Calendar (
calendar_date DATE NOT NULL,
week_number SMALLINT NOT NULL,
is_holiday BIT NOT NULL,
name VARCHAR(30) NOT NULL, -- i.e. 'January 6th, 2016'
CONSTRAINT PK_Calendar PRIMARY KEY CLUSTERED (calendar_date)
)
You can expand the table as needed, for example if accounting uses a different definition for week of the year than another department then that's easy to accommodate by adding another column. This then makes your query a simple join to get the week number:
SELECT
MT.CarTitle,
MT.ReturnDate,
CAL.week_number
FROM
My_Table MT
INNER JOIN dbo.Calendar CAL ON CAL.calendar_date = MT.ReturnDate
You'll need to populate the table, but that should be a one time effort (populate it for 50 years in advance and it's still a pretty small table) and you can use code similar to my first statement to generate the values - don't enter each date by hand ;) After that you just need to maintain the table if the business logic changes (which is easier than changing all of your queries that deal with dates) or if you get a new requirement that needs a new column.

PL/SQL Food Industry "Julian" Date Conversion

I have some 5 digits dates in a format that the food industry generally calls "Julian" dates (Warning: these are not the "Julian" dates you are familiar with. It's misused terminology that "stuck" and became the standard in the industry. Don't comment on that, it's just how it is.)
The first 3 digits of these "Julian" dates are a number representing the day of a year.
Example:
January 1 = 001
January 2 = 002
December 31 = 365 or 366
The next two digits are the last two digits of the year. 2015 = 15.
For example 22215 = August 10, 2015 (I believe).
I need an Oracle SQL statement that convers these "dates" into standard dates to join to other date data.
I'd add (count of days) -1 to 1st Jan of year
select to_date('20'||15||'01.01','yyyy.mm.dd') + 222-1 from dual
10/08/2015
A co-worker found the answer. The "DDD" format:
SELECT to_date('36515', 'DDDYY') FROM DUAL

What number formats would to_number(to_char(sysdate, 'ydddhh24mi')) produce?

We're transferring a legacy Oracle SQL application to a new platform and I cannot locate proper date format documentation.
What type of numbers would be produced by
SELECT to_number(to_char(sysdate, 'ydddhh24mi')) FROM dual
if sysdate were
January 3, 2015 at 6:04 AM
December 23, 2000 at 4:17 PM
TO_CHAR documentation for Oracle 8 is at http://docs.oracle.com/cd/A87861_01/NT817EE/index.htm; this leads to the format model documentation at http://docs.oracle.com/cd/A87861_01/NT817EE/server.817/a85397/sql_elem.htm#34512. Using the table there...
y returns the last digit of the year.
ddd returns the day of the year.
hh24 returns the military hour of the time.
mi returns the minute of the hour.
For January 3rd, 2015 # 6:04 AM this is 50030604.
For December 23rd, 2000 # 4:17 PM this is 03571617.

SQL select maximum from two time periods

I have a query, Im trying to select the maximum value from the summer period (nov-april down here) but it only gives me values from nov-dec with this query. Any ideas why?
SELECT TOP 10 Value, DateTime
FROM history
WHERE Tagname = #Tag
AND
((DateTime >= #StartYear AND DateTime < #StartWinter)
OR
(DateTime >= #FinishWinter AND DateTime < #FinishYear))
ORDER BY Value DESC
(DateTime >= startYear AND datetime < startwinter) gives you all results between jan and april 2009.
(Datetime > finishwinter and datetime < finishyear) gives all results in nov dec 09.
So, you're selecting top 10 from Jan Feb March April Nov Dec 2009. If that's what you want to select from, and you're only getting values in Nov Dec 2009, check to see that there should be values in the other months?
If #startwinter isn't year-sensitive you might also get jan-apr 2010.
Shouldn't you use a 'ORDER BY' when using 'TOP 10'?
And what locale do you live in, or, to rephrase it: what are reasonable dates for (#StartYear, #StartWinter, #FinishWinter, #FinishYear)
In Europe I expect:
StartYear = 2010-01-01
FinishYear= 2010-12-31
StartWinter=2010-12-20 (about)
FinishWinter=2010-03-20 (about)
So the first period would go from 2010-01-01 to 2010-12-20 (about) and the second from March 2010 to End of year.
So this would include the whole year, and most of it, from 03.20 to 12.20 double.
Hey thanks for the help everyone, it seems this is a problem with our historian (a linked db from sql server) so Ill take the issue up with them. I tried the query on a regular mssql db and it seeems fine...