L'interprétation de l'année à deux chiffres et de son siècle implicite semble être basée à la fois sur sa valeur et sur le NIP. Les plages de ce chevauchement, mais l'année complète est alors restreinte; il semble donc que vous puissiez utiliser une expression case qui vérifie les deux :
-- 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;
ce qui pour ces données, sur la base de vos deux exemples et des plages concernées, donne :
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
Le cas sélectionne une valeur de siècle à deux chiffres basée sur le code PIN, puis - parce qu'ils se chevauchent - la plage d'année à deux chiffres.
Si la conception des données change de sorte que les chevauchements ne sont plus uniques en fonction de l'année à deux chiffres, vous rencontrez d'autres problèmes. Il sera intéressant de voir ce qui se passera lorsque nous atteindrons 2040...
Et si vous aviez un SSN qui ne correspondait pas aux plages que vous avez affichées, dites 12105050000
(avec le code PIN 500, mais l'année à deux chiffres n'est ni comprise entre 00-39 ni 54-99), l'expression de casse renverra null et l'année à deux chiffres sera alors interprétée comme 0050. Vous pourriez faire une erreur à la place en changeant le modèle de format - dépend si cela peut arriver et comment vous voulez le gérer si c'est le cas.
Vous pouvez probablement comprendre ce bit de toute façon, mais pour gérer le scénario jour + 40 mentionné dans les commentaires, vous pouvez utiliser une autre expression de cas pour ajuster le numéro du jour :
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
...