IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

SAS Base Discussion :

Jointures transverses avec tables de hachage


Sujet :

SAS Base

  1. #1
    Futur Membre du Club
    Homme Profil pro
    Autre
    Inscrit en
    Septembre 2015
    Messages
    5
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Activité : Autre
    Secteur : Finance

    Informations forums :
    Inscription : Septembre 2015
    Messages : 5
    Points : 5
    Points
    5
    Par défaut Jointures transverses avec tables de hachage
    Bonjour tout le monde,

    Cela fait plusieurs jours que je joue avec les tables de hachage et j'ai des difficultés à "traduire" certaines jointures écrites en sql. Je cherche notamment à joindre une table principale à une table finale en passant par une table intermédiaire. Si ce n'est pas clair, le code suivant devrait l'être :

    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
    DATA large; 
       INPUT id gender $; 
       DATALINES; 
    1 F
    2 M
    3 F
    4 F
    5 M
    6 G
    7 M
    8 P
    9 F
    ; 
     
    DATA small_link; 
       INPUT gender $ key; 
       DATALINES; 
    F 1
    M 2
    G 4
    ; 
     
    DATA small_final; 
       INPUT key final; 
       DATALINES; 
    1 111
    2 222
    ; 
     
    proc sql;
    create table want as select
     
    a.*,
    b.key,
    c.final
     
    from large a
    left join small_link b on (a.gender = b.gender)
    left join small_final c on (b.key = c.key);
    quit;
    Pourriez-vous me dire, si c'est possible, comment modifier le code suivant pour intégrer la seconde jointure ?

    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
    data almost_want (drop=rc);
    	declare hash VS ();
    	rc = VS.DefineKey ('gender');
    	rc = VS.DefineData ('key');
    	rc = VS.DefineDone ();
     
    	declare hash VS2 ();
    	rc = VS2.DefineKey ('key');
    	rc = VS2.DefineData ('final');
    	rc = VS2.DefineDone ();
     
    	do until (eof1);
    		set small_link end = eof1;
    		rc = VS.add ();
    	end;
     
    	do until (eof2);
    		set small_final end = eof2;
    		rc = VS2.add ();
    	end;
     
    	do until (eof99) ;
    		set large end = eof99;
    		call missing(key, final);
    		rc = VS.find ();
    		output;
    	end;
    	stop;
    run;
    Je sais que je peux obtenir le résultat souhaité avec deux étapes data mais je souhaite optimiser mon code si cela est possible, d'autant plus que cette jointure n'est qu'une étape parmi d'autres.

    Par ailleurs, si vous avez des remarques ou suggestions sur le code, n'hésitez pas, je suis encore débutant en SAS .

    PS : J'ai initialement voulu poster ce message sur le site communities.sas.com (d'où les mots anglais dans le code) mais après inscription, je n'ai pas pu créer de nouveau post (plus précisément, je ne peux pas sélectionner de board lors de la création d'un nouveau post) ni répondre à des posts existants. Si quelqu'un a une solution à ce problème, je suis également preneur.

    PS 2 : J'ai eu du mal à trouver un titre, je suis ouvert à toute amélioration pour rendre la recherche par d'autres personnes plus efficace.

  2. #2
    Membre confirmé
    Homme Profil pro
    Consultant Finance/Assurance
    Inscrit en
    Décembre 2013
    Messages
    198
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Hauts de Seine (Île de France)

    Informations professionnelles :
    Activité : Consultant Finance/Assurance

    Informations forums :
    Inscription : Décembre 2013
    Messages : 198
    Points : 638
    Points
    638
    Par défaut
    Bonjour,

    Avec ce code j'arrive au même résultat que pour ton exemple :

    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
     
    DATA large; 
       INPUT id gender $; 
       DATALINES; 
    1 F
    2 M
    3 F
    4 F
    5 M
    6 G
    7 M
    8 P
    9 F
    ; 
     
    DATA small_link; 
       INPUT gender $ key; 
       DATALINES; 
    F 1
    M 2
    G 4
    ; 
     
    DATA small_final; 
       INPUT key final; 
       DATALINES; 
    1 111
    2 222
    ; 
     
     
    data jointure (drop=rc fc cle);
    if 0 then set small_link(rename=(key=cle));
    if 0 then set small_final(rename=(final = fin));
    if _n_ = 1 then do;
    dcl hash h1 (dataset : 'small_link(rename=(key=cle))');
    h1.definekey('gender');
    h1.definedata('cle');
    h1.definedone();
     
    dcl hash h2 (dataset : 'small_final(rename=(final = fin))');
    h2.definekey('key');
    h2.definedata('fin');
    h2.definedone();
    end;
    set large;
    rc = h1.find();
    if rc = 0 then key = cle; else key=.;
    fc = h2.find();
    if fc = 0 then final = fin;else dinal=.;
    run;
     
    proc print;
    var id gender key final;
    title 'Par Hash';
    run;
    Bon courage !

  3. #3
    Futur Membre du Club
    Homme Profil pro
    Autre
    Inscrit en
    Septembre 2015
    Messages
    5
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Activité : Autre
    Secteur : Finance

    Informations forums :
    Inscription : Septembre 2015
    Messages : 5
    Points : 5
    Points
    5
    Par défaut
    Effectivement, cette solution (en remplaçant "dinal" par "final") a l'air de marcher, merci beaucoup . J'étais persuadé d'avoir essayé quelque chose de ce genre pourtant... Je pense avoir mal interprété le fonctionnement de la fonction .find() qui semble chercher dans toutes les variables ramenées dans la boucle et non juste dans les variables de la table principale (large).

    J'ai une autre question : les deux bouts de codes suivants semblent produire le même résultat, y'a-t-il un choix meilleur (au sens de la rapidité d'exécution) que l'autre où est-ce une histoire de préférence ?

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    rc = h1.find();
    if rc = 0 then key = key; else key=.;
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    call missing (key);
    rc = h1.find();

    Dernière question : dans la déclaration des deux tables de hachage, tu renommes certaines variables, et j'ai l'erreur suivante dans le journal "The value 'SMALL_LINK(RENAME=(KEY=CLE))'n is not a valid SAS name." Cette erreur apparaît également avec les options keep et drop, est-elle dûe au fait que j'utilise la version 9.1.3 de SAS (à travers la version 4.1 de SAS EG) ?

    Le bout de code corrigé :

    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
    data jointure (drop=rc fc);
    if 0 then set small_link;
    if 0 then set small_final;
    if _n_ = 1 then do;
    dcl hash h1 (dataset : 'small_link');
    h1.definekey('gender');
    h1.definedata('key');
    h1.definedone();
     
    dcl hash h2 (dataset : 'small_final');
    h2.definekey('key');
    h2.definedata('final');
    h2.definedone();
    end;
    set large;
    rc = h1.find();
    if rc = 0 then key = key; else key=.;
    fc = h2.find();
    if fc = 0 then final = final;else final=.;
    run;

  4. #4
    Membre expérimenté
    Homme Profil pro
    Attaché statisticien
    Inscrit en
    Mai 2011
    Messages
    687
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 52
    Localisation : France, Yvelines (Île de France)

    Informations professionnelles :
    Activité : Attaché statisticien
    Secteur : Administration - Collectivité locale

    Informations forums :
    Inscription : Mai 2011
    Messages : 687
    Points : 1 581
    Points
    1 581
    Par défaut
    Bonsoir,

    sur les cas précis pris en exemple des formats pourraient très bien faire l'affaire. Néanmoins des tableaux associatifs marchent aussi bien.
    Sur tes problèmes d'optimisation je ne saurais te répondre, néanmoins tu pourrais modifier légèrement ton 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
    
    data jointure (drop=rc  fc);
    if 0 then set small_link;
    if 0 then set small_final;
    if _n_ = 1 then do;
    dcl hash h1 (dataset : 'small_link');
    h1.definekey('gender');
    h1.definedata('key');
    h1.definedone();
     
    dcl hash h2 (dataset : 'small_final');
    h2.definekey('key');
    h2.definedata('final');
    h2.definedone();
    end;
    set large;
    
    /*if rc = 0 then key = key; else key=.;
    fc = h2.find();
    if fc = 0 then final = final;else final=.;   mis en commentaire */
    
    
    rc=h1.find();
    IF RC=0 THEN fc=h2.find();
    RUN;
    Je suis un peu dubitatif sur les parties de code du type key=key...

    Sinon, ce qu'il te faudra faire attention avec les tableaux associatifs (objets hash) c'est la longueur de la signature de hachage (le nombre de "bucket") qu'il te faudra paramétrer en fonction de la taille des tables que tu as l'intention de charger dans tes tableaux associatifs.
    Si tu ne veux y charger qu'une table de 3 lignes, la valeur par défaut de hashexp qui est de 8 est sans doute beaucoup trop importe et une valeur de 3 ou 4 (je n'ose pas dire 2 ^^) devrait suffire amplement.

  5. #5
    Futur Membre du Club
    Homme Profil pro
    Autre
    Inscrit en
    Septembre 2015
    Messages
    5
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Activité : Autre
    Secteur : Finance

    Informations forums :
    Inscription : Septembre 2015
    Messages : 5
    Points : 5
    Points
    5
    Par défaut
    Citation Envoyé par JeromeMATHIAS Voir le message
    Sur les cas précis pris en exemple des formats pourraient très bien faire l'affaire.
    Bonjour Jérôme, je ne suis pas sûr d'avoir compris le sens de cette phrase, peux-tu détailler ?

    Citation Envoyé par JeromeMATHIAS Voir le message
    Je suis un peu dubitatif sur les parties de code du type key=key...
    En effet, et le code que j'ai retenu est le suivant :

    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
    data jointure (drop=rc);
    declare hash VS (hashexp:16);
    rc = VS.DefineKey ('gender');
    rc = VS.DefineData ('key');
    rc = VS.DefineDone ();
     
    declare hash VS2 (hashexp:16);
    rc = VS2.DefineKey ('key');
    rc = VS2.DefineData ('final');
    rc = VS2.DefineDone ();
     
    do until (eof1);
    	set small_link end = eof1;
    	rc = VS.add ();
    end;
     
    do until (eof2);
    	set small_final end = eof2;
    	rc = VS2.add ();
    end;
     
    do until (eof10) ;
     	set large end = eof10;
    	call missing(final, key);
    		rc = VS.find ();
    		rc = VS2.find ();
    	output;
    end;
    stop; run;
    L'idée est de faire un call missing (qui a l'avantage de marcher sur les variables numériques ou textes) sur les variables que je souhaite ramener et de regarder ensuite s'il y a une possible jointure pour ramener la valeur recherchée.
    Par contre, je ne sais pas si inclure la table directement lors de la déclaration du tableau associatif est plus rapide que de le remplir lors d'une boucle suivante (avec .add() ).


    Citation Envoyé par JeromeMATHIAS Voir le message
    Sinon, ce qu'il te faudra faire attention avec les tableaux associatifs (objets hash) c'est la longueur de la signature de hachage (le nombre de "bucket") qu'il te faudra paramétrer en fonction de la taille des tables que tu as l'intention de charger dans tes tableaux associatifs.
    Si tu ne veux y charger qu'une table de 3 lignes, la valeur par défaut de hashexp qui est de 8 est sans doute beaucoup trop importe et une valeur de 3 ou 4 (je n'ose pas dire 2 ^^) devrait suffire amplement.
    Pour apporter quelques précisions que j'ai omises dans le premier post, la table large fait en réalité 6 millions de lignes et les tables de jointure (il y en a une dizaine au total) font entre 500 et 3 000 lignes. J'ai essayé de comprendre comment bien choisir la valeur de hashexp mais il n'y a pas de réponse simple et je n'ai pas approfondi le sujet pour l'instant puisqu'une valeur de 16 ne semble pas saturer la mémoire. Si tu as plus d'infos sur le sujet, je suis à ton écoute .

    Dans une optique d'optimisation, j'ai également trouvé une macro (%SQUEEZE) qui permet de réduire les tailles des tables au strict minimum (je n'ai pas la main sur les tables de jointure et les formats sont mal ajustés), ce qui réduit en moyenne la taille des tables de jointure et leur empreinte mémoire par 2.

+ Répondre à la discussion
Cette discussion est résolue.

Discussions similaires

  1. Réponses: 0
    Dernier message: 07/04/2010, 18h53
  2. [jointure] relation avec table réflexive
    Par matech dans le forum Hibernate
    Réponses: 9
    Dernier message: 18/04/2007, 12h12
  3. Jointure de 3 tables avec un champ commun
    Par desperado007 dans le forum Langage SQL
    Réponses: 3
    Dernier message: 11/08/2005, 15h35
  4. [SQL] jointure externe avec 3 tables, comment faire ....
    Par grumbok dans le forum Langage SQL
    Réponses: 2
    Dernier message: 04/08/2005, 16h13
  5. [arborescence] jointure d'une table avec elle même ?
    Par Celelibi dans le forum Requêtes
    Réponses: 2
    Dernier message: 16/11/2004, 18h48

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo