Тълкуването на двуцифрената година и подразбиращия се век изглежда се основава както на нейната стойност, така и на ПИН кода. Диапазоните за това се припокриват, но след това цялата година е ограничена; така че изглежда, че можете да използвате case израз, който проверява и двете:
-- CTE for dummy data
with t42 (ssn) as (
select '12104900000' from dual
union all select '12105099999' from dual
union all select '01010000001' from dual
union all select '02029949902' from dual
union all select '03035450003' from dual
union all select '04049974904' from dual
union all select '05050050005' from dual
union all select '06063999906' from dual
union all select '07074090007' from dual
union all select '08089999908' from dual
)
select ssn, to_date(substr(ssn, 1, 4)
|| case
when to_number(substr(ssn, 7, 3)) between 0 and 499
and to_number(substr(ssn, 5, 2)) between 0 and 99 then '19'
when to_number(substr(ssn, 7, 3)) between 500 and 749
and to_number(substr(ssn, 5, 2)) between 54 and 99 then '18'
when to_number(substr(ssn, 7, 3)) between 500 and 999
and to_number(substr(ssn, 5, 2)) between 0 and 39 then '20'
when to_number(substr(ssn, 7, 3)) between 900 and 999
and to_number(substr(ssn, 5, 2)) between 40 and 99 then '19'
end
|| substr(ssn, 5, 2), 'DDMMYYYY') as dob
from t42;
което за тези данни, въз основа на вашите два примера и включените диапазони, дава:
SSN DOB
----------- ----------
12104900000 1949-10-12
12105099999 1950-10-12
01010000001 1900-01-01
02029949902 1999-02-02
03035450003 1854-03-03
04049974904 1899-04-04
05050050005 2000-05-05
06063999906 2039-06-06
07074090007 1940-07-07
08089999908 1999-08-08
Случаят избира двуцифрена стойност за век въз основа на ПИН кода и след това - тъй като те се припокриват - двуцифрения диапазон на годините.
Ако дизайнът на данните се промени, така че припокриванията вече не са уникални въз основа на двуцифрената година, имате допълнителни проблеми. Ще бъде интересно да видим какво ще се случи, когато стигнем до 2040...
И ако сте имали SSN, който не съответства на диапазоните, които сте показали, кажете 12105050000
(с ПИН 500, но двуцифрена година, която не е в диапазона 00-39 или 54-99), тогава изразът за регистър ще върне нула и двуцифрената година ще бъде интерпретирана като 0050. Вместо това можете да направите грешка, като промените моделът на формат - зависи дали може да се случи и как искате да се справите, ако се случи.
Вероятно можете да разберете този бит така или иначе, но за да се справите със сценария ден+40, споменат в коментарите, можете да използвате друг израз за регистър, за да коригирате номера на деня:
select ssn, to_date(
case
when substr(ssn, 1, 2) > 31 then to_char(to_number(substr(ssn, 1, 2)) - 40, 'FM99')
else substr(ssn, 1, 2)
end
|| substr(ssn, 3, 2)
|| case
when to_number(substr(ssn, 7, 3)) between 0 and 499
...