I would suggest presorting your incoming data by account, vendor, so your outcome gets to be more consistent, otherwise, depending on which vendor gets into the account first, the final outcome may vary. The following code may need some cleaning, but it seems does what you want;
data have;
input account vendor $ limit;
datalines;
101 a 2
101 b 3
102 a 2
103 a 2
105 a 2
104 a 2
102 b 3
104 c 2
103 b 2
;
run;
data _null_;
if _n_=1 then
do;
if 0 then
set have(rename=vendor=_v drop=limit);
declare hash h1(dataset:'have(rename=vendor=_v drop=limit)', multidata:'y');
h1.definekey('account');
h1.definedata(all:
'y');
h1.definedone();
declare hash want();
want.definekey('account');
want.definedata('account','vendor','limit','vendor_total');
want.definedone();
declare hiter ht_want('want');
declare hash ck();
ck.definekey('vendor');
ck.definedata('vendor','limit','vendor_total');
ck.definedone();
end;
set have end=done;
rc_want=want.check();
if rc_want ne 0 then
do;
rc_ck=ck.find();
if rc_ck ne 0 or (rc_ck=0 and vendor_total < limit) then
do;
if rc_ck ne 0 then
vendor_total=1;
else vendor_total+1;
rc_ck=ck.replace();
rc_want=want.add();
end;
else if rc_ck =0 and vendor_total >= limit then
do;
do rc=h1.find() by 0 while (rc=0);
rc_ck=ck.find(key:_v);
if rc_ck ne 0 or (rc_ck=0 and vendor_total < limit) then
do;
if rc_ck ne 0 then
vendor_total=1;
else vendor_total+1;
vendor=_v;
rc_ck=ck.replace();
rc_want=want.add();
leave;
end;
else rc=h1.find_next();
end;
if rc ne 0 then
do;
rc_ck=ck.find();
vendor_total+1;
rc_ck=ck.replace();
rc_want=want.add();
end;
end;
end;
if done then rc=want.output(dataset:'work.want');
run;
... View more