Bonjour à tous,
Je suis à la recherche d'une méthode optimale pour comparer des champs afin de détecter des clients potentiellements en double.
je travail dans SAS EG 5.1.
Contexte : j'ai une table de clients avec toutes ces appellations (les différents noms, prénoms qu'il a eu dans le temps ou dans différents systèmes) qui contient 30 millions de ligne.
En première instance les champs qui déterminent qu'ils sont potentiellement en double sont : SEXE identique, DATE DE NAISSANCE identique, NOM du client identique ou semblable, PRENOM du client identique ou semblable, NOM de la mère identique ou semblable ET numéro de client différents.
En premier lieu on procédait par comparaison SOUNDEX dans un where d'une proc SQL maintenant on veut rafiiner ces critères en rajoutant d'autres blocs de conditions c'est là ou je pêche un peu
Les conditions seraient ainsi :
1 - égalité parfaite des 5 variables et numéro de clients différents
2- son indentique des 5 variables (SOUNDEX) et numéro de clients différents
3- une lettre peu différer dans les 3 variables de noms (COMPLEV) et numéro de clients différents
4- un nom peut en contenir un autre et numéro de clients différents
J'ai tenté les 3 premieres avec des OR dans le WHERE sur 100 000 lignes et là c'est même trop long ...imaginer les 30M.
Je fais appel à vos suggestions pour optimiser, imbriquer les conditions, y aller par élimination (cdtion 1 ok...on passe àa 2 sans relire les 30M ainsi de suite...).
Un exemple de code :
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65 PROC SQL; CREATE TABLE WORK.test_clipot AS SELECT t1.NO_SEQ_CLI, t2.NO_SEQ_CLI AS NO_SEQ_CLI1, t1.NO_IDN_APP, t1.CO_SOU_APP, t1.CO_TYP_APP, t1.IN_COR, t1.NM_APP_CLI, t2.NM_APP_CLI AS NM_APP_CLI1, t1.PR_APP_CLI, t2.PR_APP_CLI AS PR_APP_CLI1, t1.DT_NAI_CLI, t1.NM_NAI_MER_CLI, t2.NM_NAI_MER_CLI AS NM_NAI_MER_CLI1, t1.AD_LIG_1, t2.AD_LIG_1 AS AD_LIG_11, t1.AD_LIG_2, t2.AD_LIG_2 AS AD_LIG_21, t1.CO_POS, t2.CO_POS AS CO_POS1, t1.NO_TEL_COM, t2.NO_TEL_COM AS NO_TEL_COM1, t1.NO_TEL_RES, t2.NO_TEL_RES AS NO_TEL_RES1, CAT(t1.AD_LIG_1," " ,t1.AD_LIG_2) as adresse_1, CAT(t2.AD_LIG_1," " ,t2.AD_LIG_2) as adresse_2 FROM EXTRACTION_APPELLATION t1, EXTRACTION_APPELLATION t2 WHERE /*Bloc egalite parfaite*/ ( t1.DT_NAI_CLI = t2.DT_NAI_CLI AND t1.CO_SEX_CLI = t2.CO_SEX_CLI AND t1.NO_SEQ_CLI NOT = t2.NO_SEQ_CLI AND t1.NM_NAI_MER_CLI = t2.NM_NAI_MER_CLI AND t1.NM_APP_CLI = t2.NM_APP_CLI AND t1.PR_APP_CLI = t2.PR_APP_CLI) OR /*Bloc similarité de son*/ ( t1.DT_NAI_CLI = t2.DT_NAI_CLI AND t1.CO_SEX_CLI = t2.CO_SEX_CLI AND t1.NO_SEQ_CLI NOT = t2.NO_SEQ_CLI AND soundex(t1.NM_NAI_MER_CLI) = soundex(t2.NM_NAI_MER_CLI) AND soundex(t1.NM_APP_CLI) = soundex(t2.NM_APP_CLI) AND soundex(t1.PR_APP_CLI) = soundex(t2.PR_APP_CLI )) OR /*Bloc similarité de son et un caractère de différend*/ ( t1.DT_NAI_CLI = t2.DT_NAI_CLI AND t1.CO_SEX_CLI = t2.CO_SEX_CLI AND t1.NO_SEQ_CLI NOT = t2.NO_SEQ_CLI AND complev(strip(t1.NM_NAI_MER_CLI),strip(t2.NM_NAI_MER_CLI))<=1 AND complev(strip(t1.NM_APP_CLI),strip(t2.NM_APP_CLI))<=1 AND complev(strip(t1.PR_APP_CLI),strip(t2.PR_APP_CLI))<=1 ) ORDER BY t1.NO_SEQ_CLI; QUIT;
Pour info j'avais des macros qui font les différents comparaison mais je ne sais pas comment l'intégrer dans mon WHERE...
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88 %let where_cond= between 0 and 10; /*********************************************************************/ /***************************** DD1AA *********************************/ /*********************************************************************/ %let trans_to='EEEEAAOOIIIUU'; %let trans_from='ÊËÉÈÂÀÔÖÎÏÌÛÙ'; %let remove="() -'."; /*********************************************************************/ /* transform */ /* */ /* Macro pour transformer une chaîne de caractères avant de faire une*/ /* comparaison. La macro enlève les accents, les blancs et certains */ /* caractères spéciaux, question que ces éléments ne viennent pas */ /* gêner la comparaison. */ /*********************************************************************/ %macro transform(string); strip( translate( compress(upcase(&string.), &remove.), &trans_to.,&trans_from.) ) %mend transform; /*********************************************************************/ /* pareil */ /* */ /* Macro qui indique si 2 chaînes de caractères sont pareils, avec un*/ /* certain degré de tolérance. Par exemple, voici les cas où les 2 */ /* chaînes sont considérées comme "pareil" : */ /* - La chaine 1 est inclue dans la chaîne 2, ou vice-versa. */ /* - Les 2 chaines sont pareils phonétiquement (avec SOUNDEX). */ /* - Il y a une différence de 1 seul caractère entre les 2 chaînes. */ /* - Une partie de la nouvelle chaîne sonne (SOUNDEX) ou est presque */ /* pareil (différence de 1 caractère acceptée) avec l'ancienne */ /* chaîne. Pour ce point, on vérifie que la nouvelle chaîne dans */ /* l'ancienne, et non l'inverse. Donc l'ordre des paramètres est */ /* important. */ /* */ /* USAGE */ /* ----- */ /* Dans un data step. */ /* */ /* data test; */ /* t1 = "allo"; */ /* t2 = "alo"; */ /* %pareil(t1, t2, p); */ /* run; */ /* */ /* Une nouvelle colonne "p" est ajoutée au dataset, et elle contient */ /* la valeur 1 si les colonnes passées en paramètre sont considérées */ /* pareil, ou 0 sinon. */ /* */ /*********************************************************************/ %MACRO pareil(anc,nouv, sortie); /* Test 1 : est-ce que le nouveau prénom contient l'ancien */ t1 = max(find(%transform(&nouv.), %transform(&anc.), 'it'), find(%transform(&anc.), %transform(&nouv.), 'it')); /* Test 2 : est-ce que le nouveau prénom sonne comme l'ancien */ t2 = (soundex(&nouv.) = soundex(&anc.)); /* Test 3 : On accepte une différence de 1 dans les noms */ t3 = complev(strip(&nouv.), strip(&anc.)); if t3 in (0,1) then t3 = 1; else t3 = 0; /* Tests 4 et 5 : Est-ce qu'une partie du nouveau prénom */ /* sonne ou s'écrit comme l'ancien */ n = 1; t4 = 0; t5 = 0; nom = scan(&nouv., n, ,'s'); do while (strip(nom) ne '' and t4=0 and t5=0); t4 = (soundex(nom) = soundex(&anc.)); t5 = complev(strip(nom), strip(&anc.)); if t5 in (0,1) then t5 = 1; else t5 = 0; n = n + 1; nom = scan(&nouv., n, ,'s'); end; &sortie. = max(t1, t2, t3, t4, t5); %MEND pareil;
Partager