As featured in: Data Management Solutions Using SAS Hash Table Operations: A Business Intelligence Case Study , and built from this github repository.
generatelineups.sas
1 /* "generatelineups.sas" from the SAS Press book
2  Data Management Solutions Using SAS Hash Table Operations:
3  A Business Intelligence Case Study
4 */
5 
6 %macro generateLineUps
7  (from =
8  ,nweeks =
9  );
10 
11  %local to;
12  %let from = %sysfunc(inputn(&from,date9.));
13  %let to = %eval(&from + &nweeks*7 - 1);
14 
15  %do date = &from %to &to;
16 
17  data _null_;
18 
19  retain Date &Date;
20  if 0 then
21  do; /* define vars to PDV */
22  set template.LineUps bizarro.Positions_Snowflake;
23  Away_SK = Team_SK;
24  Home_SK = Team_SK;
25  end; /* define vars to PDV */
26 
27  /* load hash table with number of starters for each position */
28  declare hash positions(dataset:"bizarro.Positions");
29  positions.defineKey("Position_Grp_SK");
30  positions.defineData("Position_Grp_SK","Position_Code","Count","Starters");
31  positions.defineDone();
32  declare hiter positionIter("positions");
33 
34  declare hash positions_snowflake(dataset:"bizarro.Positions_Snowflake",ordered:"A",multidata:"Y");
35  positions_snowflake.defineKey("Position_Grp_FK");
36  positions_snowflake.defineData("Position_Grp_FK","Position_Code");
37  positions_snowflake.defineDone();
38 
39  declare hash LineUp(multidata:"Y");
40  rc = LineUp.defineKey("Game_SK","Team_SK");
41  rc = LineUp.defineData("Game_SK","Team_SK","Date","Batting_Order","Player_ID","First_Name","Last_Name","Position_Code","Bats","Throws");
42  rc = LineUp.defineDone();
43 
44  declare hash players(dataset:"bizarro.Player_Candidates(where=(Team_SK))",ordered:"A",multidata:"Y");
45  rc = players.defineKey("Team_SK","Position_Code");
46  rc = players.defineData("Team_SK","Player_ID","First_Name","Last_Name","Bats","Throws");
47  rc = players.defineDone();
48 
49  do while (lr = 0);
50  set bizarro.trades end = lr;
51  where trade_date le &date;
52  do while(players.do_over(Key:_team_sk,Key:_Position_Code) = 0);
53  if player_id = traded_id then
54  do; /* player traded - delete and re-add */
55  players.removeDup();
56  team_sk = traded_to;
57  Position_Code = _Position_Code;
58  players.add();
59  leave;
60  end;
61  end;
62  end;
63 
64  declare hash games(dataset:"bizarro.Games(where=(date=&date))",multidata:"Y");
65  rc = games.defineKey("Date");
66  rc = games.defineData("Game_SK","Away_SK","Home_SK");
67  rc = games.defineDone();
68 
69  games_rc = games.find(Key:&date);
70  do while (games_rc = 0);
71  do team_sk = away_sk, home_sk;
72  rc = positionIter.first();
73  P_Grp = Position_Code;
74  grp_rc = positions_snowflake.find(Key:Position_Grp_SK);
75  do while(rc=0);
76  prc = players.find(Key:Team_SK,Key:P_grp);
77  do while(prc = 0);
78  Batting_Order = uniform(&seed5*&date);
79  if divide(Starters,Count) gt Batting_Order then
80  do; /* select this player */
81  if position_code = "SP" then Batting_Order = 9;
82  rc = LineUp.add();
83  if grp_rc = 0 then grp_rc = positions_snowflake.find_next(Key:Position_Grp_SK);
84  Starters + (-1); /* need one less player */
85  end; /* select this player */
86  else if position_code ne "SP" then
87  do; /* pinch hitters and relief pitchers */
88  _position_code = position_code;
89  if position_code = 'RP' then Batting_Order = 1e6;
90  else
91  do;/* assign as a pinch hitter for the pitcher */
92  Batting_Order + 9;
93  Position_Code = 'PH';
94  end; /* assign as a pinch hitter for the pitcher */
95  LineUp.add();
96  position_code = _position_code;
97  end; /* pinch hitters and relief pitchers */
98  Count + (-1); /* regardless have one less player */
99  prc = players.find_next(Key:Team_SK,Key:P_grp);
100  end;
101  *if Position_Code = 'UT' then
102  do; /* add utility players as PHers */;
103  * Batting_Order = 9 + uniform(&seed5*&date);
104  *Position_Code = 'PH';
105  * LineUp.add();
106  *end; /* add utility players as PHers */;
107  rc=positionIter.next();
108  P_Grp = Position_Code;
109  grp_rc = positions_snowflake.find(Key:Position_Grp_SK);
110  end;
111  end;
112  games_rc = games.find_next();
113  end;
114  LineUp.output(dataset:"Lineups");
115  stop;
116  run;
117 
118  proc sort data = lineups out = lineups;
119  by game_sk team_sk batting_order;
120  run;
121 
122  %if %sysfunc(exist(bizarro.LineUps)) %then
123  %do; /* delete existing rows for these games */
124  proc sql;
125  delete from bizarro.Lineups
126  where Game_SK in (select distinct Game_SK from Lineups);
127  quit;
128  %end; /* delete existing rows for these games */
129  %else
130  %do; /* create the initial data set */
131  data bizarro.LineUps;
132  set Lineups(obs=0);
133  run;
134  %end; /* create initial data set */
135 
136  data bizarro.LineUps(index=(LineUp=(Game_SK Team_SK)));
137  set bizarro.Lineups
138  LineUps(in = new);
139  drop Order;
140  by game_sk team_sk;
141  if first.team_sk then Order=0;
142  Order+1;
143  if batting_order ne int(batting_order) and new then batting_order = min(Order,9);
144  run;
145  %end;
146 %mend generateLineUps;