Tolkningen av det tvåsiffriga året och dess underförstådda århundrade verkar baseras både på dess värde och PIN-koden. Intervallet för det överlappar varandra, men hela året begränsas då; så det ser ut som att du kan använda ett kasusuttryck som kontrollerar båda:
-- 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;
som för dessa data, baserat på dina två exempel och de inblandade intervallen, ger:
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
Fallet väljer ett tvåsiffrigt sekelvärde baserat på PIN-koden och sedan - eftersom de överlappar - det tvåsiffriga årsintervallet.
Om datadesignen ändras så att överlappningarna inte längre är unika baserat på det tvåsiffriga året har du ytterligare problem. Det ska bli intressant att se vad som händer när vi når 2040...
Och om du hade ett SSN som inte matchade intervallen du har visat, säg 12105050000
(med PIN 500, men tvåsiffrigt årtal inte i vare sig intervallet 00-39 eller 54-99) så kommer kasusuttrycket att returnera null och det tvåsiffriga året kommer då att tolkas som 0050. Du kan göra det fel istället genom att ändra formatmodellen - beror på om det kan hända och hur du vill hantera det om det gör det.
Du kan förmodligen räkna ut det här i alla fall, men för att hantera scenariot för dag+40 som nämns i kommentarerna, kan du använda ett annat falluttryck för att justera dagnumret:
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
...