GENERICITY New Metadata Concepts Applied to SAS Macro Programming

Slides:



Advertisements
Similar presentations
PHASE-III MACRO SYSTEM A case of fractal system architecture using programming languages and procedures from SAS Institute Inc. Wolf-Dieter Batz PhUSE.
Advertisements

Haas MFE SAS Workshop Lecture 3:
Outline Proc Report Tricks Kelley Weston. Outline Examples 1.Text that spans columnsText that spans columns 2.Patient-level detail in the titlesPatient-level.
SAS Programming Techniques for Decoding Variables on the Database Level By Chris Speck PAREXEL International RTSUG – Wednesday, March 23, 2011.
1 Creating and Tweaking Data HRP223 – 2010 October 24, 2011 Copyright © Leland Stanford Junior University. All rights reserved. Warning: This.
Computer Science 1620 Loops.
Fundamentals of Python: From First Programs Through Data Structures
CC0002NI – Computer Programming Computer Programming Er. Saroj Sharan Regmi Week 7.
Fundamentals of Python: First Programs
SAS SQL SAS Seminar Series
XP New Perspectives on Microsoft Access 2002 Tutorial 51 Microsoft Access 2002 Tutorial 5 – Enhancing a Table’s Design, and Creating Advanced Queries and.
An Animated Guide©: Sending SAS files to Excel Concentrating on a D.D.E. Macro.
McGraw-Hill Technology Education © 2004 by the McGraw-Hill Companies, Inc. All rights reserved. Office Access 2003 Lab 3 Analyzing Data and Creating Reports.
Mr. Dave Clausen1 La Cañada High School Chapter 6: Repetition Statements.
WHAT IS A DATABASE? A DATABASE IS A COLLECTION OF DATA RELATED TO A PARTICULAR TOPIC OR PURPOSE OR TO PUT IT SIMPLY A GENERAL PURPOSE CONTAINER FOR STORING.
1 Chapter 9. To familiarize you with  Simple PERFORM  How PERFORM statements are used for iteration  Options available with PERFORM 2.
 2000 Deitel & Associates, Inc. All rights reserved. Chapter 10 - JavaScript/JScript: Control Structures II Outline 10.1Introduction 10.2Essentials of.
Controlling Program Flow with Decision Structures.
Using Dictionary Tables to Profile SAS Datasets By Phillip Julian February 11, 2011.
Working Efficiently with Large SAS® Datasets Vishal Jain Senior Programmer.
Hints and Tips SAUSAG Q SORTING – NOUNIQUEKEY The NOUNIQUEKEY option on PROC SORT is a useful way in 9.3 to easily retain only those records with.
CMSC201 Computer Science I for Majors Lecture 07 – While Loops
Session 1 Retrieving Data From a Single Table
Introduction to Computing Science and Programming I
Data Virtualization Tutorial: Introduction to SQL Script
Loops BIS1523 – Lecture 10.
(or SASopardy, if you will)
GC211Data Structure Lecture2 Sara Alhajjam.
Functions CIS 40 – Introduction to Programming in Python
Algorithm Analysis CSE 2011 Winter September 2018.
JavaScript: Functions.
Intro to PHP & Variables
Advanced Analytics Using Enterprise Miner
UNIT-4 BLACKBOX AND WHITEBOX TESTING
Tamara Arenovich Tony Panzarella
Chapter 10 Programming Fundamentals with JavaScript
Variables In programming, we often need to have places to store data. These receptacles are called variables. They are called that because they can change.
Topics Introduction to File Input and Output
Chapter 3 The DATA DIVISION.
CS1100 Computational Engineering
Iteration: Beyond the Basic PERFORM
Iteration: Beyond the Basic PERFORM
Loops CIS 40 – Introduction to Programming in Python
3 Iterative Processing.
Hunter Glanz & Josh Horstman
Type & Typeclass Syntax in function
Chapter 6: Repetition Statements
Python programming exercise
Never Cut and Paste Again
Producing Descriptive Statistics
Algorithms and Problem Solving
Lab 2 HRP223 – 2010 October 18, 2010 Copyright © Leland Stanford Junior University. All rights reserved. Warning: This presentation is protected.
Use of PROC TABULATE Out File to Customize Tables
Contents Preface I Introduction Lesson Objectives I-2
Spreadsheets, Modelling & Databases
Relational Database Design
CprE 185: Intro to Problem Solving (using C)
Boolean Expressions to Make Comparisons
Passing Simple and Complex Parameters In and Out of Macros
Chapter 3: Selection Structures: Making Decisions
The Selection Structure
Topics Introduction to File Input and Output
ECE 352 Digital System Fundamentals
CprE 185: Intro to Problem Solving (using C)
Error Correction Coding
Database Programming Using Oracle 11g
Module 4 Loops and Repetition 9/19/2019 CSE 1321 Module 4.
UNIT-4 BLACKBOX AND WHITEBOX TESTING
Presentation transcript:

GENERICITY New Metadata Concepts Applied to SAS Macro Programming Wolf-Dieter Batz: New Metadata Concepts

Preface What it is and what it is not This paper presents part of my experiences using SAS Macro technology over years with great pleasure and, occasionally, with some success, at least for customer satisfaction. Starting with an example from an earlier presentation the question is raised, how the positive correlation between program flexibility and number of parameters can be extinguished. By introducing the term “Reporting Specific Data Structures” one idea is described that allows to make use from metadata already present in the runtime environment. This paper is NOT about Programming using the SAS Macro Facility. Wolf-Dieter Batz: New Metadata Concepts

+ Concept Metadata Generic Programming %LOCAL i_frq n_frq l_frq i_ctl n_ctl l_ctl; %GLOBAL fct src tbl otb; %MACRO cr_tbl_4_fct; proc sql noprint; %LET n_ctl = %SCAN(&FCT.,3,'_'); %LET n_frq = %SCAN(&FCT.,2,'_'); %IF %SCAN(&FCT.,1,'_') eq PRR %THEN %DO; /* start PRR main loop */ from dictionary.columns select name into :p_key ; and varnum eq 1 and memname = %UPCASE("&TBL.") where libname = %UPCASE("&SRC.") , :l2frq separated by ' * ' , name into :l_frq separated by ' ' insert into header values("PRR values calculated for &L2FRQ."); and varnum le %EVAL(&N_FRQ. + 1) and varnum gt 1 , :l2ctl separated by ' * ' into :l_ctl separated by ' , ' and varnum le %EVAL(&N_FRQ. + &N_CTL. + 1) and varnum gt %EVAL(&N_FRQ. + 1) from &SRC..&TBL. select compbl(put(count(*),8.)||" lines processed from %UPCASE(&DB_USR.).&TBL.") insert into footer values("Stratification performed by: &L2CTL."); insert into footer select compbl("Frequency tables based on "||put(count(distinct &P_KEY.),8.)||" distinct values from field &P_KEY.") create table &SRC..c_frq as %END; , %IF &I_FRQ. gt 1 %THEN %DO; select distinct %DO i_frq = 1 %TO &N_FRQ.; %SCAN(&L_FRQ.,&I_FRQ.,' ') where and %SCAN(&L_FRQ.,&I_FRQ.,' ') is not null insert into footer values("&N_C_FRQ. combinations from &L2FRQ. processed"); %LET n_c_frq = &SQLOBS.; quit; call symput("%SCAN(&L_FRQ.,&I_FRQ.,' ')"||'_'||trim(left(put(_N_,4.))),trim(left(%SCAN(&L_FRQ.,&I_FRQ.,' ')))); set &SRC..c_frq; data _null_; run; create view WORK.tbl as proc sql; %DO i_c_frq = 1 %TO &N_C_FRQ.; /* start FREQ loop */ case %LET %SCAN(&L_FRQ.,&I_FRQ.,' ') = %QUOTE(&&%SCAN(&L_FRQ.,&I_FRQ.,' ')_&I_C_FRQ.); &P_KEY. , end as %SCAN(&L_FRQ.,&I_FRQ.,' ')_rnk , else 0 then -1 when sum( %SCAN(&L_FRQ.,&I_FRQ.,' ') = "&&%SCAN(&L_FRQ.,&I_FRQ.,' ')" ) > 0 group by &L_CTL. &P_KEY. tables &L2CTL. proc freq noprint data = WORK.tbl; output out = WORK.cmh(keep = _mhrrc1_ l_mhrrc1 u_mhrrc1) cmh1; / cmh1 %STR(*) %SCAN(&L_FRQ.,&I_FRQ.,' ')_rnk tables %SCAN(&L_FRQ.,&I_FRQ.,' ')_rnk %STR(*) output out = WORK.cmc(keep = l_mhrrc1 u_mhrrc1) cmh1; / sparse out = WORK.cnt(keep = count) data WORK.res; merge WORK.trp WORK.cmh WORK.cmc(rename=(l_mhrrc1=l_mhrrcx u_mhrrc1=u_mhrrcx)); run; proc transpose data = WORK.cnt out = WORK.trp; run; select create table WORK.out as "&&%SCAN(&L_FRQ.,&I_FRQ.,' ')" , col3 as b label = "cell B" , col2 as c label = "cell C" , col1 as a label = "cell A" as %SCAN(&L_FRQ.,&I_FRQ.,' ') , u_mhrrcx as cmhucrude label = "PRR crude upper CL" , _mhrrc1_ as cmh_strat label = "PRR stratified" , l_mhrrcx as cmhlcrude label = "PRR crude lower CL" , (a/c)*((c+d)/(a+b)) as cmh_crude label = "PRR crude" , col4 as d label = "cell D" from WORK.res , l_mhrrc1 as cmhlstrat label = "PRR stratified lower CL" , u_mhrrc1 as cmhustrat label = "PRR stratified upper CL" create table &SRC..&TBL.%SCAN(&FCT.,1,_) as drop table &SRC..&TBL.%SCAN(&FCT.,1,_); %IF &I_C_FRQ. = 1 %THEN %DO; union from &SRC..&TBL.%SCAN(&FCT.,1,_) select * %IF &I_C_FRQ. > 1 %THEN %DO; from out %END; /* end FREQ loop */ %IF %SUBSTR(&RST.,2,1) ne C %THEN %DO; join &SRC..&TBL. as fct right from &SRC..&TBL.%SCAN(&FCT.,1,_) as tbl %IF %SUBSTR(&RST.,1,1) ne R %THEN %DO; on = tbl.%SCAN(&L_FRQ.,&I_FRQ.,' ') fct.%SCAN(&L_FRQ.,&I_FRQ.,' ') %ELSE %DO; %END; /* end PRR main loop */ %LET tbl = &TBL.%SCAN(&FCT.,1,_); %LET otb = &TBL.; %MEND cr_tbl_4_fct; Concept + Metadata Wolf-Dieter Batz: New Metadata Concepts

“A problem well stated is a problem half solved“ Never forget “A problem well stated is a problem half solved“ Charles Kettering (1876-1958) Founder of the General Motors Research Corporation Wolf-Dieter Batz: New Metadata Concepts

Np = f(F) Number of Parameters Flexibility Wolf-Dieter Batz: New Metadata Concepts

When producing reports Intro When producing reports You might end up with One appropriately sized program per report One somehow macroized program per report type One Macro System for reporting domains Wolf-Dieter Batz: New Metadata Concepts

Start For example: Wolf-Dieter Batz: New Metadata Concepts

This Quest Wolf-Dieter Batz: New Metadata Concepts

generated by a single macro system Wolf-Dieter Batz: New Metadata Concepts

System Architecture User Modules Core Modules Info Modules Generate datasets carrying subtables controlled by user-supplied parms Core Modules Perform input transformation, calculations and output transformation Info Modules Provide information about datasets and variables for correct processing Service Modules Provide frequently requested tasks in a standard format with limited parameter set Wolf-Dieter Batz: New Metadata Concepts

Required already a few parameters Program Controlling Required already a few parameters Wolf-Dieter Batz: New Metadata Concepts

full parameter set – user modules %TWO_BOBO() – Build super row (=block) from boolean selections nested in boolean selection dsn input dataset name row, row2 categorial variable name, 2=list of nested_var#true_value rev Y/N (output decodes of &ROW in reverse order) use, use2 select decode from &ROW, 2=decode from &ROW used as nesting context weight Y/N (multiply percentages for &ROW and &ROW2) col categorial variable name used for columns total T/I/B/O/N/TC/IC/BC/OC/NC head, head2 Y/N (block header, 2=nested variable) indent, indinc n (number of indent columns and increment for nested variable) num n (sequence number of output) stat Y/N (column with statistics names) space 1/2/3 (blank line before or after output and between nesting levels) struct, struct2 name of reference dataset used for full decode structure, 2=nested variable condense var#value (non-distinct variable and true value for &ROW) misslin2 Y/N (force missing line for nested variable) Wolf-Dieter Batz: New Metadata Concepts

user parameters - common DSN: Name of input dataset or view. This may be any valid SAS dataset name (one-level or two-level) not accompanied by dataset options or other SAS syntax components. COL: Name of variable used to construct columns. The variable is checked for number of levels and an appropriate number of columns are generated. ROW: Name of variable to construct rows, superrows, and subtables. Modules capable of processing more than one variable accept a list here. HEAD: Optionally specify “N” to suppress output of the header line for the row variable generated from their label. In categorial processing the header is an additional 1st line whereas in continuous processing the header text is written left-hand to the 1st stats line output. Default is “Y”. STAT: Optionally select “Y” to generate an output column which contains the names of statistics generated. Default is “N”. INDENT: Optionally select a positive integer to indent the rows generated as one block. Default is “0”. SPACE: Optionally select spacing mode for one-level subtables: 0=no blank lines; 1=1st output line is blank; 2=last output line is blank. Default is “2”. For two-level subtables: 2=insert additional blank line between upper and lower level output; 3=only last output line is a blank line. Default is “3”. NUM: Assigns a unique number to the output generated. Only one digit is allowed here. Wolf-Dieter Batz: New Metadata Concepts

This appears quite complicated Not amused This appears quite complicated Isn’t there another way To have limited source code With a high level of flexibility And not to drown in parameter flood Let’s have a closer look… Wolf-Dieter Batz: New Metadata Concepts

When running macro programs Talk to me When running macro programs You may influence results on several levels Parameter passing (“feed”) Controlling (“feed and prevent”) Communication (“feed, prevent and search”) Wolf-Dieter Batz: New Metadata Concepts

Make your Macro a curious Communicator Search Make your Macro a curious Communicator Implement a search mechanism that makes it follow a set of rules provides or generates knowledge on metadata in reach is fault-tolerant Wolf-Dieter Batz: New Metadata Concepts

Of course, this should be a Macro because you want to Search Of course, this should be a Macro because you want to do it once do it generic use it forever Wolf-Dieter Batz: New Metadata Concepts

Metadata are all around Simple variable lists: “-NUMERIC-” Libref “dictionary”: tables, columns, etc. User defined repositories of any kind Wolf-Dieter Batz: New Metadata Concepts

Report Specific Data Structures Let’s focus on one One of the frequently neglected or simply overseen information bits from dictionary.columns is VARNUM. This may result from historical reasons, since the SAS dataset structure was learned as more or less fixed. Reordering a dataset’s variables was not supported very well by the SAS System and hence, not used. Since concepts emerge from programming habits… Wolf-Dieter Batz: New Metadata Concepts

Report Specific Data Structures SQL Views Today, since 1990, it is very easy to reorder the “virtual physical” sequence of variables in a dataset. The SAS System treats the properties of an SQL view equally to those of an old-fashioned somewhat “clumsy” SAS Dataset. This is good News! Wolf-Dieter Batz: New Metadata Concepts

Report Specific Data Structures Let’s try a small example: Wolf-Dieter Batz: New Metadata Concepts

Report Specific Data Structures data testdsn; label a=Variable A in SAS Dataset b=Variable B in SAS Dataset ; a=22; b=190; run; proc sql; create view testsql as select b as a label="Variable B from SAS Dataset" , a as b label="Variable A from SAS Dataset" from testdsn ; select memname , name , label , varnum from dictionary.columns where memname like 'TEST___' ; quit; Wolf-Dieter Batz: New Metadata Concepts

Report Specific Data Structures Member Name Column Name Column Label Column Number in Table TESTDSN a Variable A in SAS Dataset 1 b Variable B in SAS Dataset 2 TESTSQL Variable B from SAS Dataset Variable A from SAS Dataset Wolf-Dieter Batz: New Metadata Concepts

Report Specific Data Structures Access Layer Obviously, utilizing the select clause in an SQL view adds a high amount of information to the data structure. This is not surprising, in case you are a physicist can count from zero to 1023 using ten fingers Wolf-Dieter Batz: New Metadata Concepts

Information Gain by Ordering Source: http://courses.geoplanet.ca/ice3m/image/binary_hand_1-7.gif Wolf-Dieter Batz: New Metadata Concepts

Report Specific Data Structures Now let’s have a look a real life: Wolf-Dieter Batz: New Metadata Concepts

Report Specific Data Structures Wolf-Dieter Batz: New Metadata Concepts

Report Specific Data Structures Wolf-Dieter Batz: New Metadata Concepts

Resulting Output Wolf-Dieter Batz: New Metadata Concepts

Howto Wolf-Dieter Batz: New Metadata Concepts %LOCAL i_frq n_frq l_frq i_ctl n_ctl l_ctl; %GLOBAL fct src tbl otb; %MACRO cr_tbl_4_fct; proc sql noprint; %LET n_ctl = %SCAN(&FCT.,3,'_'); %LET n_frq = %SCAN(&FCT.,2,'_'); %IF %SCAN(&FCT.,1,'_') eq PRR %THEN %DO; /* start PRR main loop */ from dictionary.columns select name into :p_key ; and varnum eq 1 and memname = %UPCASE("&TBL.") where libname = %UPCASE("&SRC.") , :l2frq separated by ' * ' , name into :l_frq separated by ' ' insert into header values("PRR values calculated for &L2FRQ."); and varnum le %EVAL(&N_FRQ. + 1) and varnum gt 1 , :l2ctl separated by ' * ' into :l_ctl separated by ' , ' and varnum le %EVAL(&N_FRQ. + &N_CTL. + 1) and varnum gt %EVAL(&N_FRQ. + 1) from &SRC..&TBL. select compbl(put(count(*),8.)||" lines processed from %UPCASE(&DB_USR.).&TBL.") insert into footer values("Stratification performed by: &L2CTL."); insert into footer select compbl("Frequency tables based on "||put(count(distinct &P_KEY.),8.)||" distinct values from field &P_KEY.") create table &SRC..c_frq as %END; , %IF &I_FRQ. gt 1 %THEN %DO; select distinct %DO i_frq = 1 %TO &N_FRQ.; %SCAN(&L_FRQ.,&I_FRQ.,' ') where and %SCAN(&L_FRQ.,&I_FRQ.,' ') is not null insert into footer values("&N_C_FRQ. combinations from &L2FRQ. processed"); %LET n_c_frq = &SQLOBS.; quit; call symput("%SCAN(&L_FRQ.,&I_FRQ.,' ')"||'_'||trim(left(put(_N_,4.))),trim(left(%SCAN(&L_FRQ.,&I_FRQ.,' ')))); set &SRC..c_frq; data _null_; run; create view WORK.tbl as proc sql; %DO i_c_frq = 1 %TO &N_C_FRQ.; /* start FREQ loop */ case %LET %SCAN(&L_FRQ.,&I_FRQ.,' ') = %QUOTE(&&%SCAN(&L_FRQ.,&I_FRQ.,' ')_&I_C_FRQ.); &P_KEY. , end as %SCAN(&L_FRQ.,&I_FRQ.,' ')_rnk , else 0 then -1 when sum( %SCAN(&L_FRQ.,&I_FRQ.,' ') = "&&%SCAN(&L_FRQ.,&I_FRQ.,' ')" ) > 0 group by &L_CTL. &P_KEY. tables &L2CTL. proc freq noprint data = WORK.tbl; output out = WORK.cmh(keep = _mhrrc1_ l_mhrrc1 u_mhrrc1) cmh1; / cmh1 %STR(*) %SCAN(&L_FRQ.,&I_FRQ.,' ')_rnk tables %SCAN(&L_FRQ.,&I_FRQ.,' ')_rnk %STR(*) output out = WORK.cmc(keep = l_mhrrc1 u_mhrrc1) cmh1; / sparse out = WORK.cnt(keep = count) data WORK.res; merge WORK.trp WORK.cmh WORK.cmc(rename=(l_mhrrc1=l_mhrrcx u_mhrrc1=u_mhrrcx)); run; proc transpose data = WORK.cnt out = WORK.trp; run; select create table WORK.out as "&&%SCAN(&L_FRQ.,&I_FRQ.,' ')" , col3 as b label = "cell B" , col2 as c label = "cell C" , col1 as a label = "cell A" as %SCAN(&L_FRQ.,&I_FRQ.,' ') , u_mhrrcx as cmhucrude label = "PRR crude upper CL" , _mhrrc1_ as cmh_strat label = "PRR stratified" , l_mhrrcx as cmhlcrude label = "PRR crude lower CL" , (a/c)*((c+d)/(a+b)) as cmh_crude label = "PRR crude" , col4 as d label = "cell D" from WORK.res , l_mhrrc1 as cmhlstrat label = "PRR stratified lower CL" , u_mhrrc1 as cmhustrat label = "PRR stratified upper CL" create table &SRC..&TBL.%SCAN(&FCT.,1,_) as drop table &SRC..&TBL.%SCAN(&FCT.,1,_); %IF &I_C_FRQ. = 1 %THEN %DO; union from &SRC..&TBL.%SCAN(&FCT.,1,_) select * %IF &I_C_FRQ. > 1 %THEN %DO; from out %END; /* end FREQ loop */ %IF %SUBSTR(&RST.,2,1) ne C %THEN %DO; join &SRC..&TBL. as fct right from &SRC..&TBL.%SCAN(&FCT.,1,_) as tbl %IF %SUBSTR(&RST.,1,1) ne R %THEN %DO; on = tbl.%SCAN(&L_FRQ.,&I_FRQ.,' ') fct.%SCAN(&L_FRQ.,&I_FRQ.,' ') %ELSE %DO; %END; /* end PRR main loop */ %LET tbl = &TBL.%SCAN(&FCT.,1,_); %LET otb = &TBL.; %MEND cr_tbl_4_fct; %LET n_frq = %SCAN(&FCT.,2,'_'); %LET n_ctl = %SCAN(&FCT.,3,'_'); Wolf-Dieter Batz: New Metadata Concepts

Howto Wolf-Dieter Batz: New Metadata Concepts select name into :p_key %LOCAL i_frq n_frq l_frq i_ctl n_ctl l_ctl; %GLOBAL fct src tbl otb; %MACRO cr_tbl_4_fct; proc sql noprint; %LET n_ctl = %SCAN(&FCT.,3,'_'); %LET n_frq = %SCAN(&FCT.,2,'_'); %IF %SCAN(&FCT.,1,'_') eq PRR %THEN %DO; /* start PRR main loop */ from dictionary.columns select name into :p_key ; and varnum eq 1 and memname = %UPCASE("&TBL.") where libname = %UPCASE("&SRC.") , :l2frq separated by ' * ' , name into :l_frq separated by ' ' insert into header values("PRR values calculated for &L2FRQ."); and varnum le %EVAL(&N_FRQ. + 1) and varnum gt 1 , :l2ctl separated by ' * ' into :l_ctl separated by ' , ' and varnum le %EVAL(&N_FRQ. + &N_CTL. + 1) and varnum gt %EVAL(&N_FRQ. + 1) from &SRC..&TBL. select compbl(put(count(*),8.)||" lines processed from %UPCASE(&DB_USR.).&TBL.") insert into footer values("Stratification performed by: &L2CTL."); insert into footer select compbl("Frequency tables based on "||put(count(distinct &P_KEY.),8.)||" distinct values from field &P_KEY.") create table &SRC..c_frq as %END; , %IF &I_FRQ. gt 1 %THEN %DO; select distinct %DO i_frq = 1 %TO &N_FRQ.; %SCAN(&L_FRQ.,&I_FRQ.,' ') where and %SCAN(&L_FRQ.,&I_FRQ.,' ') is not null insert into footer values("&N_C_FRQ. combinations from &L2FRQ. processed"); %LET n_c_frq = &SQLOBS.; quit; call symput("%SCAN(&L_FRQ.,&I_FRQ.,' ')"||'_'||trim(left(put(_N_,4.))),trim(left(%SCAN(&L_FRQ.,&I_FRQ.,' ')))); set &SRC..c_frq; data _null_; run; create view WORK.tbl as proc sql; %DO i_c_frq = 1 %TO &N_C_FRQ.; /* start FREQ loop */ case %LET %SCAN(&L_FRQ.,&I_FRQ.,' ') = %QUOTE(&&%SCAN(&L_FRQ.,&I_FRQ.,' ')_&I_C_FRQ.); &P_KEY. , end as %SCAN(&L_FRQ.,&I_FRQ.,' ')_rnk , else 0 then -1 when sum( %SCAN(&L_FRQ.,&I_FRQ.,' ') = "&&%SCAN(&L_FRQ.,&I_FRQ.,' ')" ) > 0 group by &L_CTL. &P_KEY. tables &L2CTL. proc freq noprint data = WORK.tbl; output out = WORK.cmh(keep = _mhrrc1_ l_mhrrc1 u_mhrrc1) cmh1; / cmh1 %STR(*) %SCAN(&L_FRQ.,&I_FRQ.,' ')_rnk tables %SCAN(&L_FRQ.,&I_FRQ.,' ')_rnk %STR(*) output out = WORK.cmc(keep = l_mhrrc1 u_mhrrc1) cmh1; / sparse out = WORK.cnt(keep = count) data WORK.res; merge WORK.trp WORK.cmh WORK.cmc(rename=(l_mhrrc1=l_mhrrcx u_mhrrc1=u_mhrrcx)); run; proc transpose data = WORK.cnt out = WORK.trp; run; select create table WORK.out as "&&%SCAN(&L_FRQ.,&I_FRQ.,' ')" , col3 as b label = "cell B" , col2 as c label = "cell C" , col1 as a label = "cell A" as %SCAN(&L_FRQ.,&I_FRQ.,' ') , u_mhrrcx as cmhucrude label = "PRR crude upper CL" , _mhrrc1_ as cmh_strat label = "PRR stratified" , l_mhrrcx as cmhlcrude label = "PRR crude lower CL" , (a/c)*((c+d)/(a+b)) as cmh_crude label = "PRR crude" , col4 as d label = "cell D" from WORK.res , l_mhrrc1 as cmhlstrat label = "PRR stratified lower CL" , u_mhrrc1 as cmhustrat label = "PRR stratified upper CL" create table &SRC..&TBL.%SCAN(&FCT.,1,_) as drop table &SRC..&TBL.%SCAN(&FCT.,1,_); %IF &I_C_FRQ. = 1 %THEN %DO; union from &SRC..&TBL.%SCAN(&FCT.,1,_) select * %IF &I_C_FRQ. > 1 %THEN %DO; from out %END; /* end FREQ loop */ %IF %SUBSTR(&RST.,2,1) ne C %THEN %DO; join &SRC..&TBL. as fct right from &SRC..&TBL.%SCAN(&FCT.,1,_) as tbl %IF %SUBSTR(&RST.,1,1) ne R %THEN %DO; on = tbl.%SCAN(&L_FRQ.,&I_FRQ.,' ') fct.%SCAN(&L_FRQ.,&I_FRQ.,' ') %ELSE %DO; %END; /* end PRR main loop */ %LET tbl = &TBL.%SCAN(&FCT.,1,_); %LET otb = &TBL.; %MEND cr_tbl_4_fct; select name into :p_key from dictionary.columns where libname = %UPCASE("&SRC.") and memname = %UPCASE("&TBL.") and varnum eq 1 ; Wolf-Dieter Batz: New Metadata Concepts

Howto Wolf-Dieter Batz: New Metadata Concepts select name , name %LOCAL i_frq n_frq l_frq i_ctl n_ctl l_ctl; %GLOBAL fct src tbl otb; %MACRO cr_tbl_4_fct; proc sql noprint; %LET n_ctl = %SCAN(&FCT.,3,'_'); %LET n_frq = %SCAN(&FCT.,2,'_'); %IF %SCAN(&FCT.,1,'_') eq PRR %THEN %DO; /* start PRR main loop */ from dictionary.columns select name into :p_key ; and varnum eq 1 and memname = %UPCASE("&TBL.") where libname = %UPCASE("&SRC.") , :l2frq separated by ' * ' , name into :l_frq separated by ' ' insert into header values("PRR values calculated for &L2FRQ."); and varnum le %EVAL(&N_FRQ. + 1) and varnum gt 1 , :l2ctl separated by ' * ' into :l_ctl separated by ' , ' and varnum le %EVAL(&N_FRQ. + &N_CTL. + 1) and varnum gt %EVAL(&N_FRQ. + 1) from &SRC..&TBL. select compbl(put(count(*),8.)||" lines processed from %UPCASE(&DB_USR.).&TBL.") insert into footer values("Stratification performed by: &L2CTL."); insert into footer select compbl("Frequency tables based on "||put(count(distinct &P_KEY.),8.)||" distinct values from field &P_KEY.") create table &SRC..c_frq as %END; , %IF &I_FRQ. gt 1 %THEN %DO; select distinct %DO i_frq = 1 %TO &N_FRQ.; %SCAN(&L_FRQ.,&I_FRQ.,' ') where and %SCAN(&L_FRQ.,&I_FRQ.,' ') is not null insert into footer values("&N_C_FRQ. combinations from &L2FRQ. processed"); %LET n_c_frq = &SQLOBS.; quit; call symput("%SCAN(&L_FRQ.,&I_FRQ.,' ')"||'_'||trim(left(put(_N_,4.))),trim(left(%SCAN(&L_FRQ.,&I_FRQ.,' ')))); set &SRC..c_frq; data _null_; run; create view WORK.tbl as proc sql; %DO i_c_frq = 1 %TO &N_C_FRQ.; /* start FREQ loop */ case %LET %SCAN(&L_FRQ.,&I_FRQ.,' ') = %QUOTE(&&%SCAN(&L_FRQ.,&I_FRQ.,' ')_&I_C_FRQ.); &P_KEY. , end as %SCAN(&L_FRQ.,&I_FRQ.,' ')_rnk , else 0 then -1 when sum( %SCAN(&L_FRQ.,&I_FRQ.,' ') = "&&%SCAN(&L_FRQ.,&I_FRQ.,' ')" ) > 0 group by &L_CTL. &P_KEY. tables &L2CTL. proc freq noprint data = WORK.tbl; output out = WORK.cmh(keep = _mhrrc1_ l_mhrrc1 u_mhrrc1) cmh1; / cmh1 %STR(*) %SCAN(&L_FRQ.,&I_FRQ.,' ')_rnk tables %SCAN(&L_FRQ.,&I_FRQ.,' ')_rnk %STR(*) output out = WORK.cmc(keep = l_mhrrc1 u_mhrrc1) cmh1; / sparse out = WORK.cnt(keep = count) data WORK.res; merge WORK.trp WORK.cmh WORK.cmc(rename=(l_mhrrc1=l_mhrrcx u_mhrrc1=u_mhrrcx)); run; proc transpose data = WORK.cnt out = WORK.trp; run; select create table WORK.out as "&&%SCAN(&L_FRQ.,&I_FRQ.,' ')" , col3 as b label = "cell B" , col2 as c label = "cell C" , col1 as a label = "cell A" as %SCAN(&L_FRQ.,&I_FRQ.,' ') , u_mhrrcx as cmhucrude label = "PRR crude upper CL" , _mhrrc1_ as cmh_strat label = "PRR stratified" , l_mhrrcx as cmhlcrude label = "PRR crude lower CL" , (a/c)*((c+d)/(a+b)) as cmh_crude label = "PRR crude" , col4 as d label = "cell D" from WORK.res , l_mhrrc1 as cmhlstrat label = "PRR stratified lower CL" , u_mhrrc1 as cmhustrat label = "PRR stratified upper CL" create table &SRC..&TBL.%SCAN(&FCT.,1,_) as drop table &SRC..&TBL.%SCAN(&FCT.,1,_); %IF &I_C_FRQ. = 1 %THEN %DO; union from &SRC..&TBL.%SCAN(&FCT.,1,_) select * %IF &I_C_FRQ. > 1 %THEN %DO; from out %END; /* end FREQ loop */ %IF %SUBSTR(&RST.,2,1) ne C %THEN %DO; join &SRC..&TBL. as fct right from &SRC..&TBL.%SCAN(&FCT.,1,_) as tbl %IF %SUBSTR(&RST.,1,1) ne R %THEN %DO; on = tbl.%SCAN(&L_FRQ.,&I_FRQ.,' ') fct.%SCAN(&L_FRQ.,&I_FRQ.,' ') %ELSE %DO; %END; /* end PRR main loop */ %LET tbl = &TBL.%SCAN(&FCT.,1,_); %LET otb = &TBL.; %MEND cr_tbl_4_fct; select name , name into :l_frq separated by ' ' , :l2frq separated by ' * ' from dictionary.columns where libname = %UPCASE("&SRC.") and memname = %UPCASE("&TBL.") and varnum gt 1 and varnum le %EVAL(&N_FRQ. + 1) ; Wolf-Dieter Batz: New Metadata Concepts

Howto Wolf-Dieter Batz: New Metadata Concepts select name , name %LOCAL i_frq n_frq l_frq i_ctl n_ctl l_ctl; %GLOBAL fct src tbl otb; %MACRO cr_tbl_4_fct; proc sql noprint; %LET n_ctl = %SCAN(&FCT.,3,'_'); %LET n_frq = %SCAN(&FCT.,2,'_'); %IF %SCAN(&FCT.,1,'_') eq PRR %THEN %DO; /* start PRR main loop */ from dictionary.columns select name into :p_key ; and varnum eq 1 and memname = %UPCASE("&TBL.") where libname = %UPCASE("&SRC.") , :l2frq separated by ' * ' , name into :l_frq separated by ' ' insert into header values("PRR values calculated for &L2FRQ."); and varnum le %EVAL(&N_FRQ. + 1) and varnum gt 1 , :l2ctl separated by ' * ' into :l_ctl separated by ' , ' and varnum le %EVAL(&N_FRQ. + &N_CTL. + 1) and varnum gt %EVAL(&N_FRQ. + 1) from &SRC..&TBL. select compbl(put(count(*),8.)||" lines processed from %UPCASE(&DB_USR.).&TBL.") insert into footer values("Stratification performed by: &L2CTL."); insert into footer select compbl("Frequency tables based on "||put(count(distinct &P_KEY.),8.)||" distinct values from field &P_KEY.") create table &SRC..c_frq as %END; , %IF &I_FRQ. gt 1 %THEN %DO; select distinct %DO i_frq = 1 %TO &N_FRQ.; %SCAN(&L_FRQ.,&I_FRQ.,' ') where and %SCAN(&L_FRQ.,&I_FRQ.,' ') is not null insert into footer values("&N_C_FRQ. combinations from &L2FRQ. processed"); %LET n_c_frq = &SQLOBS.; quit; call symput("%SCAN(&L_FRQ.,&I_FRQ.,' ')"||'_'||trim(left(put(_N_,4.))),trim(left(%SCAN(&L_FRQ.,&I_FRQ.,' ')))); set &SRC..c_frq; data _null_; run; create view WORK.tbl as proc sql; %DO i_c_frq = 1 %TO &N_C_FRQ.; /* start FREQ loop */ case %LET %SCAN(&L_FRQ.,&I_FRQ.,' ') = %QUOTE(&&%SCAN(&L_FRQ.,&I_FRQ.,' ')_&I_C_FRQ.); &P_KEY. , end as %SCAN(&L_FRQ.,&I_FRQ.,' ')_rnk , else 0 then -1 when sum( %SCAN(&L_FRQ.,&I_FRQ.,' ') = "&&%SCAN(&L_FRQ.,&I_FRQ.,' ')" ) > 0 group by &L_CTL. &P_KEY. tables &L2CTL. proc freq noprint data = WORK.tbl; output out = WORK.cmh(keep = _mhrrc1_ l_mhrrc1 u_mhrrc1) cmh1; / cmh1 %STR(*) %SCAN(&L_FRQ.,&I_FRQ.,' ')_rnk tables %SCAN(&L_FRQ.,&I_FRQ.,' ')_rnk %STR(*) output out = WORK.cmc(keep = l_mhrrc1 u_mhrrc1) cmh1; / sparse out = WORK.cnt(keep = count) data WORK.res; merge WORK.trp WORK.cmh WORK.cmc(rename=(l_mhrrc1=l_mhrrcx u_mhrrc1=u_mhrrcx)); run; proc transpose data = WORK.cnt out = WORK.trp; run; select create table WORK.out as "&&%SCAN(&L_FRQ.,&I_FRQ.,' ')" , col3 as b label = "cell B" , col2 as c label = "cell C" , col1 as a label = "cell A" as %SCAN(&L_FRQ.,&I_FRQ.,' ') , u_mhrrcx as cmhucrude label = "PRR crude upper CL" , _mhrrc1_ as cmh_strat label = "PRR stratified" , l_mhrrcx as cmhlcrude label = "PRR crude lower CL" , (a/c)*((c+d)/(a+b)) as cmh_crude label = "PRR crude" , col4 as d label = "cell D" from WORK.res , l_mhrrc1 as cmhlstrat label = "PRR stratified lower CL" , u_mhrrc1 as cmhustrat label = "PRR stratified upper CL" create table &SRC..&TBL.%SCAN(&FCT.,1,_) as drop table &SRC..&TBL.%SCAN(&FCT.,1,_); %IF &I_C_FRQ. = 1 %THEN %DO; union from &SRC..&TBL.%SCAN(&FCT.,1,_) select * %IF &I_C_FRQ. > 1 %THEN %DO; from out %END; /* end FREQ loop */ %IF %SUBSTR(&RST.,2,1) ne C %THEN %DO; join &SRC..&TBL. as fct right from &SRC..&TBL.%SCAN(&FCT.,1,_) as tbl %IF %SUBSTR(&RST.,1,1) ne R %THEN %DO; on = tbl.%SCAN(&L_FRQ.,&I_FRQ.,' ') fct.%SCAN(&L_FRQ.,&I_FRQ.,' ') %ELSE %DO; %END; /* end PRR main loop */ %LET tbl = &TBL.%SCAN(&FCT.,1,_); %LET otb = &TBL.; %MEND cr_tbl_4_fct; select name , name into :l_ctl separated by ' , ' , :l2ctl separated by ' * ' from dictionary.columns where libname = %UPCASE("&SRC.") and memname = %UPCASE("&TBL.") and varnum gt %EVAL(&N_FRQ. + 1) and varnum le %EVAL(&N_FRQ. + &N_CTL. + 1) ; Wolf-Dieter Batz: New Metadata Concepts

Questions welcome Wolf-Dieter Batz: New Metadata Concepts

THANK YOU Wolf-Dieter Batz: New Metadata Concepts