4
votes

Comment renvoyez-vous dans SAS la liste de toutes les colonnes de toutes les tables d'une bibliothèque contenant une valeur cible?

J'essaie de mapper les champs que je vois dans une application aux colonnes de la base de données source à l'aide de SAS EG.

Si je recherche "SomeString" ou someNumericValue dans Library = SomeLibrary Je veux que le code produise une table qui répertorie le nom de la table ColumnName qui contient la valeur recherchée.

Proc SQL: Sélectionnez * les colonnes C de toutes les tables de la bibliothèque L qui contiennent la valeur ou la chaîne = 'SomeValue'


0 commentaires

3 Réponses :


0
votes

Grand défi! Je peux vous y aider - la macro mp_searchdata de la bibliothèque SASjs macro core interrogera toutes les tables d'une bibliothèque (base de données source) pour une chaîne ou une valeur numérique. Il renvoie toutes les colonnes, mais ne filtre que les enregistrements correspondants.

Pour exécuter:

/* import library */
filename mc url "https://raw.githubusercontent.com/sasjs/core/main/all.sas";
%inc mc;

/* run macro */
%mp_searchdata(lib=yourlib, string=SomeString)


2 commentaires

J'obtiens les erreurs suivantes en essayant d'exécuter ceci: ERREUR: La connexion a été réinitialisée par un pair. ERREUR: Impossible d'ouvrir le fichier% INCLUDE MC. Même lorsque je copie le code, j'obtiens une erreur en essayant d'exécuter la macro: ERREUR 180-322: l'instruction n'est pas valide ou elle est utilisée dans le mauvais ordre.


vous n'avez peut-être pas accès à partir de votre serveur Web. Il suffit de télécharger et de compiler les macros séparément: raw.githubusercontent.com/sasjs/core/ main / all.sas



0
votes

C'est une bonne question, j'ai moi-même voulu développer le code pour moi .. vous pouvez essayer le code suivant pour trouver les noms de table à partir d'une bibliothèque, des noms de variables exacts qui ont la valeur requise

Code modifié h1 >
libname temp "Y:\temp\t";
data temp.aa;
a=0;
b=0;
test="String";
run;

data temp.bb;
a=1;
c=0;
d=1;
run;

data temp.cc;
a=0;
b=1;
e=1;
run;

proc sql;
create table info
as
select memname as table, name as column from dictionary.columns
where upcase(type)="NUM" /*upcase(type)="CHAR"*/
and libname='TEMP'
order by memname;
quit;

options merror mprint nosymbolgen nomlogic;
data info1;
length coltab $1000.;
 set info;
 newtab=catx("_","TEMPT",_n_);
 condition=column||"=1"; /*Set Desired value here*/
 tab=("'"||table||"' as tab_name");
 var=("'"||column||"' as var_name");
 coltab="create table "||newtab||" as Select "||column||","||tab||","||var||" from temp."||table|| "where "||condition||";";
run;

proc sql noprint;
select count(*) into: nobs from info1;
quit;

%macro process;
%do i=1 %to &nobs;
    Data _null_;
        Set info1(firstobs=&i obs=&i);
        call symput('query',coltab);
    run;
    proc sql noprint;
        &Query;
    quit;
%end;
%mend;

%process;

proc sql noprint;
select distinct memname into :gt separated by " " from dictionary.columns where memname like '%TEMPT%';
quit;

%macro split(var);
%let var_c=%sysfunc(countw(&var));
%do i=1 %to &var_c;
    %let var_t=%sysfunc(scan(&var,&i));

    proc sql noprint;
    select count(*) into :cnt from &var_t;
    quit;

    %if &cnt=0 %then
    %do;
        proc datasets lib=work nolist;   
        delete &var_t; 
        quit;
        run;
    %end;
%end;
%mend split;

%split(&gt);

proc sql noprint;
select distinct memname into :gt0 separated by " " from dictionary.columns where memname like '%TEMPT%';
quit;

data all;
 set &gt0;
 keep tab_name var_name;
run;

proc sort data=all; by tab_name; run;

data final;
length vars $100.;
 set all;
  by tab_name;
  retain vars '';
  if first.tab_name then vars=var_name;
  else vars=catx(",",vars,var_name);
  if last.tab_name;
  drop var_name;
run;

proc print data=final; run;


4 commentaires

J'obtiens l'erreur suivante après avoir changé ma chaîne de recherche et ma variable. Ma chaîne ne comporte que 10 caractères ... ERREUR: La longueur de la valeur de la variable macro COLTAB (65540) dépasse la longueur maximale (65534). La valeur a été tronquée à 65534 caractères.


Je ne sais pas trop si ce code gère les tables / ensembles de données qui ont un mélange de variables de caractères et numériques. Existe-t-il un moyen d'ignorer les colonnes numériques lors de l'itération?


J'ai modifié le code de votre première erreur, ça devrait aller maintenant. Parce que maintenant, il passera en boucle sur chaque observation et exécutera la requête séparément, au lieu de créer une grande chaîne.


Aussi, pour répondre à votre deuxième préoccupation - oui, vous pouvez contrôler les types char / num en fonction de la logique - upcase (type) = "CHAR" .. ou "NUM" lors de l'extraction des données de dictionary.columns. J'ai donc modifié un peu le jeu de données d'exemple et inclus une variable de caractère pour votre référence. J'utilise uniquement des nombres et j'ignore les caractères, vous pouvez faire l'inverse .. donc si vous souhaitez rechercher une chaîne, changez cette ligne: condition = colonne || "= 'String'"; / * Définissez la valeur souhaitée ici * / et utilisez upcase (type) = "CHAR"



0
votes

Contenu du processus peut créer une table des noms de jeux de données à analyser. Une macro d'analyse, par exemple % scanner , peut être écrite et appelée pour chaque ensemble de données via call execute . Les résultats de l'analyse, le nom de l'ensemble de données et la colonne contenant la cible, peuvent être ajoutés à un tableau «tous les résultats».

Exemple:

Par souci de simplicité, il est présumé qu'aucun ensemble de données ne contient plus de Variables 10K du type de valeur cible - le code émet un avertissement si l'analyse sera tronquée.

Remarque: Un exemple de chaîne cible serait ..., target = "Jane",. ..

%macro scanner (libname=, memname=, target=20500, flagMax = 10000);
  %local type;

  %if %qsysfunc(dequote(&target)) = %superq(target) %then 
    %let type = _numeric_;
  %else 
    %let type = _character_;

  data hits(keep=__libname __memname __varname);
    array __flag (&flagMax) _temporary_;

    set &libname..&memname;

    array __candidates &type;

    if dim(__candidates) = 0 then stop;

    do __index = 1 to min (dim(__candidates), &flagMax);
      if not __flag(__index) then 
        if __candidates(__index) = &target then do;
          length __libname $8;
          length __memname __varname $32;
          __libname = "&libname";
          __memname = "&memname";
          __varname = vname(__candidates(__index));
          __flag(__index) = 1;

          OUTPUT;
        end;          
    end;

    if _n_ = 1 then
      if dim(__candidates) > &flagMax then put "WARNING: &memname has more than &flagMax variables - scanning will be clipped. Increase flagMax=.";
  run;

  proc append base=hasTarget data=hits(rename=(__libname=libname __memname=memname __varname=varname));
  run;
%mend;

proc sql;
  create table hasTarget (libname char(8), memname char(32), varname char(32));
quit;

%let libname = SASHELP;

ods noresults;
ods output members=datasets;
proc datasets library=&libname memtype=data;
run;
quit;
ods results;

data _null_;
  set datasets(keep=name memtype);
  where memtype = 'DATA';

  call execute (cats('%nrstr(%scanner(libname=' || "&LIBNAME., " || "memname=", name, '))'));
run;


5 commentaires

En outre, comment ignorer des tables spécifiques dans la bibliothèque recherchée? par exemple, dans a des tables A, B, C, D et je sais que la table C est grande et non pertinente, puis-je dire à la macro de sauter la table C dans l'automatisation?


Ajoutez un where ou if aux données _null_ finales avant l ' exécution qui lance les analyses. Par exemple: if NOT (libname = "BIGGY" and memname = "C");


Solution incroyable!


Où est-ce que je spécifie la bibliothèque à rechercher: dans % let libname = SASHELP; changer SASHELP en ma bibliothèque? Puis confirmant la partie de la chaîne, changez la valeur de la chaîne dans target = 20500 en quelque chose comme target = "Jane" ?


Vous pouvez les spécifier directement dans call execute . call execute (cats ('% nrstr (% scanner (target = "Jane", libname = MyLib, memname =', name, '))'));