BookmarkSubscribeRSS Feed
lc_isp
Obsidian | Level 7

Good morning all,

 

as I'm not that expert in SAS programming (still waiting to be trained but, as usual, trying to be productive in the meantime) I'm having a problem to figure out how to launch/call a SAS EG process' "step #2" from a program macro I wrote into same process' step #1 (forgive me if I won't use the correct SAS terms too: still learning).

 

More details: my customer asked our team to retrieve bank transactions data, two years from "today" (date()) giving us customers codes. I'm not sure my approach is the best one but, as I'm not exactly an analyst but a programmer, I wrote the following:

 

process step 1:

 

  1. import the "requests" (Excel) file into a WORK.REQUESTS temporary table: multiple records with 4 fields, containing the customer's code we need

  2. import step leads to a "looping" program which reads such table, record by record (observations), extracts the fields (variables) and writes another temp table WORK.REQUEST (singular) so that next steps have variables available.

 

EC24Mproj_step1EC24Mproj_step1

 

mainLoop program:

options timezone=cet;
/*	Questa macro legge, in sequenza, tutti i record importati dagli step precedenti,
per ogni record crea, ex novo, una tabella temporanea (WORK.RICHIESTA) contenente
un solo record di 4 campi (esattamente uguale al formato della tabella importata).
 Quindi lancia una query che, leggendo quel record, esegue tutti i successivi passi
della procedura, fino ad esportare i file richiesti.

(C)2022 - Intesa Sanpaolo - DC OP AML Inv and Sanction Filtering - Regole e Strumenti
*/
%macro loopOverTable();
	%local recCount Contratto;

	/* step #1: retrieve the inported table's RecordCount
		 in: WORK.EC24M_RICHIESTE
		out: recCount (macro var)
	*/
	PROC SQL;
	   SELECT count(*)
			  into :recCount
	      from WORK.EC24M_RICHIESTE t1;
	QUIT;

	%let ix=1;										/* init ix index */

	/* debugging & performances */
	%let tStart=%sysfunc(datetime());				/* whole time computing */
	%let tStop=%sysfunc(datetime());				/* single step time computing */

	/* DEBUG: redefine recCount to avoid looping the whole table (while developing) */
	/*%let recCount=3;*/
	/* DEBUG: redefine recCount to avoid looping the whole table */

	%if(&recCount > 0) %then						/* no requests for the day -> recCount = zero */
		%do %while (&ix <= &recCount);
			data _NULL_;
				/* step #2: create a single record WORK.EC24M_RICHIESTA table, with all 4 fields
					 in: ix (record index)
					out: Filiale, Categoria, Conto, contratto (1 record from WORK.EC24M_RICHIESTE, pointed by ix)
				*/
				set WORK.EC24M_RICHIESTE (firstobs=&ix. obs=&ix.);
				call symput("Contratto", strip(contratto));	/* retrieved variable will be NUMERIC */

				proc sql;
					create table WORK.EC24M_RICHIESTA as
						select t1.Filiale,
							   t1.Categoria,
							   t1.Conto,
							   t1.contratto
							from WORK.EC24M_RICHIESTE t1
							where t1.contratto = "&Contratto.";	/* "&Contratto." typecasts NUMERIC -> STRING */
				quit;
			run;	/* data */

			%put Contratto(&ix): &Contratto;

			/* At this point we have a (new) table, WORK.RICHIESTA with a single record, 4 fields:
				Filiale
				Categoria
				Conto
				contratto

				Now we should launch Procedure's step 02 (which, in turn, will launch the next steps too)
			*/

			/*
				/-- LAUNCH STEP 02 HERE --\
			*/

			/* ........................... */

			/*
				\-- LAUNCH STEP 02 HERE --/
			*/

			/* Debug & Performances: show current ix */
			%PUT Current index = &ix;					/* leave a track in the log */
			%let ix=%eval(&ix.+1);						/* next record: ix++ */

			/* Debug & Performances: calculate single cycle dT */
			%let deltaT=%sysevalf(%sysfunc(datetime())-&tStop);
			%put Step run time = &deltaT sec;
			%let deltaT=%sysevalf(%sysfunc(datetime())-&tStart);
			%put Cumulative run time = &deltaT sec;
			%let tStop=%sysfunc(datetime());			/* update time ref*/
			%put ;

		%end;											/* do loop */
	%else;												/* if recCount == 0 do nothing (for now) */
	/* Debug & Performances: calculate total dT */
	%let deltaT=%sysevalf(%sysfunc(datetime())-&tStart);
	%put Total run time = &deltaT sec;
%mend;

/* Loops over imported file's records, launching the next steps giving them access to record's fields by means
  of a temp table (1 rec).

	 in: WORK.EC24M_RICHIESTE	5 fields, N records
	out: WORK.RICHIESTA			4 fields, 1 record
*/
%loopOverTable()

(mainLoop code)


process step 2:

 

  1. my team is designing SAS EG process which reads the single observation from table WORK.REQUEST and, basing on a variable ("contratto"), extracts the yearly data for "current" and "previous" years (if available)
  2. next sub/steps triggered by step2a (...etc. etc...): it will end by exporting a number (5 or 6) of Excel files per customer code, depending on transactions data have been found.

 

EC24M_step2EC24M_step2

 

Step1 works already, and I'm having the single observation work table with variables.

 

The problem is: how, in step1b macro mainLoop can I "call" the whole step2 execution, like one can do by hand from SAS EG project? (or a sub-step, still in step2, or, if "step boundary" is a problem, even a sub-step 1c still into step1, which then triggers next ones)

 

That to avoid to select ALL the data, which can be huge amount, then sub-select the ones we need: by asking for the least data since beginning, the project's life could last longer, imho.

 

Thanks in advance to whoever will be able to give an hint for our needs, or give an alternative way to have the same results.

 

14 REPLIES 14
SASKiwi
PROC Star

If I understand your question correctly, it is not possible to call an EG project / process from within a SAS program. SAS programs run on a SAS server so there is no way for that program to call an EG process which runs within EG on a PC. You can however export a SAS program from an EG process, save it as a SAS program and then use the %INCLUDE statement in another SAS program to call the exported program.

AlanC
Barite | Level 11
EG is a C# based platform. It is both possible to read the egp file, pull out the relevant steps, and execute them using integration technologies. Do you need EG? Not technically, but practically, yes.

My only point is absolutism. It is both posdible to execute the code elements within the EG project and get the results by essentially mimicking what EG does using .net code and call it via an X command. However, it is much easier to do it using EG.

I will show a bit of the EG unwinding at SESUG.
https://github.com/savian-net
Patrick
Opal | Level 21

As @SASKiwi points out SAS EG is a Windows client. The code you define is kept within a .egp file. If you execute a program flow then EG will send the code to the SAS server for execution - but the SAS server can't reach back to the EG client to include the code of previous nodes. 

You can store your code on the server instead of the EG project (under save as... and then you select the server) and then you can %include such code in your scripts (program nodes).

 

From what you describe you've got some driver table (input Excel) where you then need to execute a whole bunch of things per row in your Excel. 

This sounds to me more like something you would create a macro for with the driver tables value as input parameters - and then eventually a data step with call execute() calling the macro once per row in the driver table. 

 

What's much more efficient would be by-group processing. If that's possible will depend on the details of your data and requirements.

 

btw: you can open .egp files with WinZip or the like and look what's "in-it". That might give you a better understanding how things actually work and what's client and what's server.

lc_isp
Obsidian | Level 7

Adding more details to the original post:

 

  1. despite me and my 2 co-teamers have still to be trained, I'm more a programmer (have been network admin for 10 years, up to 15 years ago), while they have more experience on data, having been "data users" in the past: if it was up to me, the whole process was probably "programmed" (pure code and macros), if it was up to them, as they don't know programming, the whole process was all done by SAS EG "interactive elements". So, at now, we're mixing our expertises trying to use programs (written by me) when needed (around 10/20% of the process) and EG, elements configured/parametrized by them (around 80% of the whole process). That's why I'm trying to call their "elements" from my macro.
    I'm also not aware if is there an EG "loop element" to use, which can "call" process' parts by passing variables into a single observation.

  2. that's also why we can't have all as a program: I can't develop the whole process and they can't program (time is our limit, at the moment). Also, in the future, we'll have to maintain the project, both code and EG elements.

  3. after we'll (hopefully) have developed the project, it will be automatically run, server side, by SAS EG Scheduler, without any human intervention (input Excel file apart, which is made by another team, our (internal) customer, who will also receive the result files).

 If is there an alternative way, to process a "request list" (the Excel input file) by a SAS EG process, without the need to use a program or macro, to call the next steps, we're eager to learn how to use it.

 

 The main problem, I believe, is our process flow is not straightforward: we'll need to do different things, depending on the data extracted by the first (SAS EG) querybuilder:

  1.  if data, selected by using the request's "code" (from input file) will cover 2 years, we'll split them into "current" and "previous" years,
  2. (exporting both intervals as "raw table" Excel files: transactions),
  3. then we'll group them (SAS work tables, not export files) by using 4 different criteria (causal, counterpart, cash, cash percentage over other payment methods) exporting 1 file for each group comparing current and previous years (incoming/outgoing amounts, transactions number for each row, delta columns to all previous ones).

But, if selected data at pt.1 covers 1 year only (or less) we'll

  1. just export the single year data
  2. grouping that anyway by the 4 different criteria, but then just exporting them into 4 single files without adding the previous year for comparison nor the delta columns

 Being not a simple "extract and report" process, I thought to extract the single "request" (code) from input file containing N of them (e.g. 10-20 per day) and launching the abovementioned procedure against the single code, looping over all codes, to try working on the minimum possible data amount (as the transactions table is really huge and can cover many years).

Patrick
Opal | Level 21

@lc_isp 

about 2)
You rush things now and you will have a maintenance nightmare later

 

about 3)

There is no full server side EG automation. EG is the client. There is client side scheduling available that can run you EG project - but it requires your EG session to be established and your client environment (your laptop) to be running. That's something some business users might be doing for their stuff but it's certainly not something fully production worthy and it's also certainly not something beyond the scope of "personal use".

 

Given your background I'll be clear:

Not having the skills (yet) to do the job right is not really a good reason to do things badly.

 

You can use EG as your development tool but if you want full automation then you need all the code server side and schedule it server side. 

You can always use point & click generated code as your starting point to create the final productionized server side code.

 

I've been in projects where users with the business knowledge created EG flows mostly via point & click which I then took as starting point to create production worthy code that can be run in batch without EG. It's possible to do as long as you manage these business users with well defined hand-over points. 

 

I still remember one project where I was supposed to help a business user to fix an overcomplicated EG project ...and it was a total nightmare. While I was fixing the project this user changed another version of the EG project multiple times and didn't understand that these are totally separate versions for the bits stored client side - and then there were also bits stored server side and this user changed the code while I was supposed to fix it. ....just the worst example from personal experience that makes me talk about maintenance nightmare when it comes to the illusion of "production worthy EG projects". They simply don't exists.

 

If you want to develop such things with a GUI based client then it's SAS DI Studio for SAS 9.4 and in the hopefully no more that far future it will be SAS Studio Engineer for SAS Viya (already available now but not yet with the same functionality than SAS DI Studio).

lc_isp
Obsidian | Level 7

 Thank you for the info, Patrick.

 Even with my little SAS knowledge I can see how much you're rightr: I'm absolutely sure we'll have nightmare maintenance but, as usual, our company placed the cart beyond the oxes (we): only thing we can do, right now, is to try achieving "a result in some way" and, later, when we'll have more knowledge (maybe trained too), hammer the process to make it better.

 

 That said, speaking with my co-teamers (which are point&click ones), we landed to the "worse possible solution" (IMHO), to select all the data about all the requests (so to avoid, for the moment, to deal with my "macro problem") then to progressively filter them down to the export files we need, making it a classic batch "select and report" process.

 The only reason I'm agreeing (for the moment) to that, is we're not going to extract that much data, globally: we did a test, today, with 3 codes, obtaining 7921 observations (2 years span for each code). Considering we'll have 10-20 codes daily, I'm not seeing we're going to extract real "big data": up to the time we'll be able to correctly tailor the process I bet we can survive: our red-line is 16 Sep for UAT and 23 Sep to release v1.0 (still an alpha, to me, tho).

 

 In the meantime we're training "in the field", so we'll see how it will go in the long term. Thank you very much for your advices, I'm looking into them too (opened the project, client-side, as zip to look at the various datasets on my PC).

 

 Last but not least, about SAS EG Scheduler: the colleague who suggested that tool is using it extensively, and his projects, despite the fact they've been developed with classic SAS EG (point&click too, as he don't know programming), have been exported then server-side scheduled (as far as we can see), without his further intervention and/or the need he is logged to the system at all: it's still "SAS Enterprise Guide" (v7.15) but the Files menu have a Schedule submenu, while the usual SAS EG client we're using have the "plan <projectname>" submenu only (which leads, as you told, to client-side scheduling).

 The reason why we're using the Scheduler is: (1) our customer can't have a SAS license by his own and (2) they need daily scheduling while my office have not the resources to do it client-side (we're 7 only and overbooked on many other tasks), plus some (client-side) authorization problems.

AlanC
Barite | Level 11
If you want to control EG, or do what it does, look up my github code and do what you need to do. EG is great for people that do clicky-clicky. It is a fantastic program.

I code and dont need that. Everything in EG is doable w/o EG. Use IntTech, call SAS server directly and bypass EG. If you need to read existing code fr an EG project, you can do that. It is all in XML.

However, you need to use c#. I am happy to help if you get the infrastructure ready. I can send code samples as needed.
https://github.com/savian-net
lc_isp
Obsidian | Level 7

TYVM Alan,

 

the C# thing interests me for sure and I hope I'll have the time, after all the fuss about our current project will end, to look more in deep into your GitHub code. At the time I've simply not the knowledge and time to do it: let's hope in the future.

AlanC
Barite | Level 11

The SAS dev team determined that the best way to work with SAS on a server was using ,NET. That was 20 years ago. .NET is now way, way more functional and covers all operating systems. The sooner you manage SAS using .NET (C#), the better. 

 

Your world with SAS will change once you move to a managed infrastructure with modern tech. I 100% get that it isn't easy right now but please make it a priority. I am happy to help, gratis, to aid you in the direction you need. Reach out to me on github and I will throw a project or two to help get you on the way.

 

https://github.com/savian-net
Patrick
Opal | Level 21

Here the docu in regards of EG scheduling https://go.documentation.sas.com/doc/en/egdoccdc/8.2/egug/p120m0y084zc3ln136lcseq41alx.htm 

The user/client that executes the code must have a valid SAS Server license. Else you're in breach. ...and if there is a valid license then you can run stuff fully server side in batch.

Quentin
Super User

Hi.  I don't use point-and-click EG, but if I were on a team where I had to integrate SAS code/macros (which I write) with EG process flows developed by someone else, I would look to the EG users to develop the outline how their process flows will work, with holes for my SAS code / macros.  Then I would write the SAS code to fill in those holes.

 

Which is to say, rather than have my SAS macro be a controller which tries to call a step from a process flow, I would let the EG process flow be the controller and call my SAS code when needed.  EG process flows have loops etc.  

 

Again, I've never done that, but I think it's how I would approach it, if I would be in your scenario.  I know with DI Studio, there are some companies that have teams of DI studio developers who only point-and-click to create jobs (similar to EG process flows).  And on rare occasions they will call on a programmer to write a "user-written code" node when there is something they can't get point-and-click.

BASUG is hosting free webinars Next up: Mark Keintz presenting History Carried Forward, Future Carried Back: Mixing Time Series of Differing Frequencies on May 8. Register now at the Boston Area SAS Users Group event page: https://www.basug.org/events.
AlanC
Barite | Level 11
A very, very easy way of handling this is via RPA. Power Automate, free with Windows, and simply record the action, like a macro in Excel.
https://github.com/savian-net
lc_isp
Obsidian | Level 7

Thank You, Quentin,

 

and yes, I came to the assumption I've to reverse my approach too: we're going to have a SAS EG process, totally point&click so I'm more probably going to "fill the holes" with some code: if my programs/macros have not to call anything else, they probably can work seamless.

lc_isp
Obsidian | Level 7

 Still trying to create a program/macro to loop over the imported table record, then submitting the main SAS EG (point&click) process by passing a single "input" (a code) to it, so to work with minimal data.

 As it seemed not viable to "call a SAS EG (graphic) item" via macro, a friend suggested me to split my macro in two:

1. mainLoop: the looping one, which reads a (now 3 obs) imported table (WORK.EC24M_RICHIESTE) and write a single obs one (WORK.EC24M_RICHIESTA), time by time

2. singleRec: a new macro, which read the single obs table written by the looping one (WORK.EC24M_RICHIESTA) and does nothing (I made it writing another single obs table (WORK.EC24M_RICHIESTA_SHORT), just for testing/debug purposes)

 

Thus I got to this situation:

mainLoop calling singleRecmainLoop calling singleRec

 

as you can see, there is no "link" from mainLoop macro to Estrazione_movimenti querybuilder, which then leads to the remaining project's steps: I linked singleRec to it, instead, expecting it, when engaged by mainLoop

 

(...)
			/* At this point we have a (new) table, WORK.RICHIESTA with a single record, 4 fields:
				Filiale, Categoria, Conto, contratto
				Now we should launch Procedure's step 02 (which, in turn, will launch the next steps too)
			*/
			data _NULL_;
				call execute ('%singleRec()');
			run;
(...)

to run the querybuilder too.

 

My thoughts was: mainLoop can't be linked to the querybuilder, 'cause if I do, it will loop N times then engages it (so the querybuilder will have the last record only, to work on) but, if I call N times singleRec, which is linked to the querybuilder, then the query will receive a different record (from the chain mainLoop -> singleRec) every time, which was my initial target (so that my colleagues can keep working point&click and I can keep looking at formulas, programs and macros).

 

...but...

 

 SAS seems not liking my way of thinking (it's probably still me I don't know SAS way of thinking): mainLoop executes and loops 3 times (as the input table is of 3 obs), it engages singleRec all the 3 times, after writing the single obs table, but the querybuilder (Estrazione_movimenti), linked to singleRec, never start.

 

 During the last week I read a lot of docs, together with many "solutions", here, in StackOverflow, everywhere.

 

 I tried such "link" by using %include %singleRec(); which worked but, being singleReg there, doing nothing at all but just being linked to the querybuilder, this way did nothing too.

 

 I tried using rc = dosubl('%singleRec()'); which brought me to a different problem (you know "every single solution will give two problems" ;-)), receiving a  buffer length error of some kind (I didn't identified the effective problem source, to be honest).

 

 My last try was the abovementioned call execute, which works, but not "as expected": is there a way, if I link a program to a querybuilder, to make the querybuilder run, after the program ends?

 

P.S.

I had doubts that call execute worked, as I read it lead to the execution after the calling element (mainLoop) ended, that's why I tried using dosubl, which I read it executes immediately. But, all apart, it seems call execute launches singleRec at every loop step (which is what I wanted), so I probably misunderstood the docs.

sas-innovate-2024.png

Available on demand!

Missed SAS Innovate Las Vegas? Watch all the action for free! View the keynotes, general sessions and 22 breakouts on demand.

 

Register now!

SAS Enterprise Guide vs. SAS Studio

What’s the difference between SAS Enterprise Guide and SAS Studio? How are they similar? Just ask SAS’ Danny Modlin.

Find more tutorials on the SAS Users YouTube channel.

Click image to register for webinarClick image to register for webinar

Classroom Training Available!

Select SAS Training centers are offering in-person courses. View upcoming courses for:

View all other training opportunities.

Discussion stats
  • 14 replies
  • 1702 views
  • 5 likes
  • 5 in conversation