Interpretace dvoumístného roku a jeho implikovaného století se zdá být založena jak na jeho hodnotě, tak na PIN. Rozsahy se pro toto překrývají, ale celý rok je pak omezen; takže to vypadá, že můžete použít výraz case, který kontroluje obojí:
-- 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;
což pro tato data na základě vašich dvou příkladů a příslušných rozsahů dává:
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
Případ vybere dvoumístnou hodnotu století na základě kódu PIN a poté – protože se překrývají – dvoumístného rozsahu roku.
Pokud se návrh dat změní, takže překryvy již nejsou jedinečné na základě dvoumístného roku, máte další problémy. Bude zajímavé sledovat, co se stane, až dosáhneme roku 2040...
A pokud jste měli SSN, které neodpovídalo rozsahům, které jste zobrazili, řekněte 12105050000
(s PIN 500, ale dvouciferným rokem není ani v rozsahu 00-39 ani 54-99), pak výraz případu vrátí hodnotu null a dvouciferný rok bude interpretován jako 0050. Místo toho můžete udělat chybu tím, že změníte model formátu – závisí na tom, zda se to může stát a jak s tím chcete zacházet, pokud ano.
Na to pravděpodobně stejně přijdete, ale abyste zvládli scénář den+40 zmíněný v komentářích, můžete k úpravě čísla dne použít jiný případ:
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
...