BookmarkSubscribeRSS Feed
🔒 This topic is solved and locked. Need further help from the community? Please sign in and ask a new question.
CatM
Obsidian | Level 7

Hi Everyone, 

 

i need to figure out how to loop through a list of numbers using a macro/do loop. I have tried the same approach as a list of variables but that doesn't seem to work at all. I need to run the code for a set of clinic numbers but don't want to have to change the clinic number and run it a million times if it can be avoided. 

 

thanks!

 

cat 

 


%macro doit(list);
%let n=%sysfunc(countw(&list));
%do i=1 %to &n;
%let val = %scan(&list,&i);
%mend;
%doit(124 70 76 57 79 221);
proc sql;

CONNECT to odbc(dsn=dbwh);
CREATE TABLE bftest as SELECT * from connection to odbc
(
SELECT P.FileDate, CLINICID,
SUM( Mo0Count) as Mo0Count1, Mo0CountTotal, R.PACKET,
CASE WHEN convert(float, Mo0CountTotal) > 0
THEN SUM(Mo0Count) / convert(float, Mo0CountTotal)
ELSE 0 END as Mo0FEEDPercent
FROM dbo.BreastfeedingEthnicity as P
JOIN dbo.Dates D
ON p.FileDate = D.DateText
JOIN (SELECT *,
CASE WHEN PGLABEL = 'IB -BF Fully' THEN 'FullyBF'
WHEN PGLABEL = 'IF -Formula' THEN 'FORMULA'
WHEN PGLABEL IN ('IC -BF Mostly', 'IO -BF Some') THEN 'MOSTSOME'
ELSE '' END AS PACKET
FROM dbo.PacketGroupReference) as R
ON P.PacketGroup = R.PacketGroup
JOIN ( SELECT FileDate, SUM(Mo0Count) as Mo0CountTotal
FROM dbo.BreastfeedingEthnicity as P
WHERE FileDate >= '2017-10'
AND AgencyID = 314 AND ClinicID = %doit
GROUP BY CLINICID, FILEDATE ) as T
ON P.FileDate = T.FileDate

WHERE P.FileDate >= '2017-10'
AND AGENCYID =314
AND CLINICID = %doit
GROUP BY CLINICID, P.FileDate, Mo0CountTotal, PACKET
ORDER BY CLINICID, P.FILEDATE
);
%end;
quit;

1 ACCEPTED SOLUTION

Accepted Solutions
Tom
Super User Tom
Super User

Please post code using the Insert Code or Insert SAS Code button.

The code you posted before appears to be summing the same variable in two different places, without using an alias to indicate what actual value of that variable you are summing.  Which version is not getting the result you want?

 

It looks like you are actually running that SQL code in some remote database that you connect to with ODBC.  So perhaps you need to query on a forum for that database about any issues that system has with performing aggregate functions?

 

 

View solution in original post

9 REPLIES 9
Krueger
Pyrite | Level 9

I feel like you have over complicated this, are you wanting to do a MACRO or use SQL to accomplish this? Use of both seems redundant and over complicating it.

 

If your going to use a MACRO then just plug in your DOIT list. 

 

If your going to use SQL Pass Through then just do a simple WHILE loop:

 

DECLARE @i int = 0

WHILE @i < 20
BEGIN
    SET @i = @i + 1
    /* do some work */
END

Performance wise CTE's may be the way to go for this however. https://docs.microsoft.com/en-us/sql/t-sql/queries/with-common-table-expression-transact-sql?view=sq...

CatM
Obsidian | Level 7

so what should it look like if i choose to go with the CTE code for the list of clinics i have 

mkeintz
PROC Star

You are using the macro %doit to present a sequence of values that you merely compare to CLINICID.  So you are producing this expression:

 

CLINICID=124 70 76 57 79 221;

Instead you probably want

CLIICID in (124,70,76,57,79,221)

 

So I suggest you don't make a macor DOIT, but instead make a macro variable (call is CSVLIST), as in:

 

%let csvlist=124,70,76,57,79,221;

at the beginning/

 

Then, inside the PROC SQL you could use

clinicid in (&csvlist)

In other words, get data for all clinics of interest at once in data set BFTEST, sorted by CLINICID (you already have ORDER BY CLINICID).

 

Then later, to analyze each clininc in BFTEST (say it is a proc reg for each clinicid), you can:

 

proc reg data=bftest ….. ;
  by clinicid ;
  model …;
quit;

which does the analysis for each level of clinicid that you put in bftest.  I've put ellipses where you need to fill out the analysis program.

--------------------------
The hash OUTPUT method will overwrite a SAS data set, but not append. That can be costly. Consider voting for Add a HASH object method which would append a hash object to an existing SAS data set

Would enabling PROC SORT to simultaneously output multiple datasets be useful? Then vote for
Allow PROC SORT to output multiple datasets

--------------------------
CatM
Obsidian | Level 7

I had tried this orginally but because of the sum command i have in the SQL this would cause all my totals to add up and i need the totals by clinic. 

Tom
Super User Tom
Super User

@CatM wrote:

I had tried this orginally but because of the sum command i have in the SQL this would cause all my totals to add up and i need the totals by clinic. 


If you want to use the aggregate SUM() function in SQL to get the sum for groups then use the GROUP BY clause in the query.

Something like this:

select id,sum(x) as sum_x
from have
group by id
where id in (&idlist)
;
CatM
Obsidian | Level 7

yes i have the code formatted with the group by and where statements for the tables. for some reason it is still adding up multiple totals and different counts for the same clinic and time point 

sas_1.JPG

Tom
Super User Tom
Super User

Please post code using the Insert Code or Insert SAS Code button.

The code you posted before appears to be summing the same variable in two different places, without using an alias to indicate what actual value of that variable you are summing.  Which version is not getting the result you want?

 

It looks like you are actually running that SQL code in some remote database that you connect to with ODBC.  So perhaps you need to query on a forum for that database about any issues that system has with performing aggregate functions?

 

 

CatM
Obsidian | Level 7

specifying the specific count i needed to print out from the second piece of code where i asked for the sum worked! thanks!

mkeintz
PROC Star

You could do a sum function with group by clinicid+ other variables in a select clause, then INNER JOIN that selection with the original data on some unique match where that "outer" selection does a sum associated with group by clinicid only.

 

Example using SASHELP.CLASS, retrieving weight for individual, then summing weight for each SEX*AGE group, then also summing for each SEX:

 

proc sql;
  select a.name,a.weight,a.sex,a.age,sumw_by_sex_age,sum(weight) as sumw_by_sex
  from sashelp.class as a
  inner join
    (select sum(b.weight) as sumw_by_sex_age 
     from sashelp.class  as b
     group by b.sex,b.age)
  on a.name=b.name
  group by a.sex
  order by a.sex,a.age
  ;
quit;

 

I have no idea of how efficient this might be.  But it can be done.

--------------------------
The hash OUTPUT method will overwrite a SAS data set, but not append. That can be costly. Consider voting for Add a HASH object method which would append a hash object to an existing SAS data set

Would enabling PROC SORT to simultaneously output multiple datasets be useful? Then vote for
Allow PROC SORT to output multiple datasets

--------------------------

Ready to join fellow brilliant minds for the SAS Hackathon?

Build your skills. Make connections. Enjoy creative freedom. Maybe change the world. Registration is now open through August 30th. Visit the SAS Hackathon homepage.

Register today!
How to Concatenate Values

Learn how use the CAT functions in SAS to join values from multiple variables into a single value.

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
  • 9 replies
  • 1819 views
  • 3 likes
  • 4 in conversation