Clinwright Public work of Helper Software LLC · free Start free

ADTR

Tumor Results Analysis Dataset

BASIC DATA STRUCTURE · one record per subject per parameter per assessment · keys STUDYID, USUBJID, PARAMCD, AVISITN

Variables

VariableLabelTypeLengthDerivation
STUDYIDStudy IdentifiertextPredecessor TR.STUDYID
USUBJIDUnique Subject IdentifiertextPredecessor TR.USUBJID
SITEIDStudy Site IdentifiertextPredecessor ADSL.SITEID
AGEAgeinteger8Predecessor ADSL.AGE
SEXSextextPredecessor ADSL.SEX
TRT01PPlanned Treatment for Period 01textPredecessor ADSL.TRT01P
TRT01AActual Treatment for Period 01textPredecessor ADSL.TRT01A
SAFFLSafety Population FlagtextPredecessor ADSL.SAFFL
ITTFLIntent-To-Treat Population FlagtextPredecessor ADSL.ITTFL
RANDDTDate of Randomizationinteger8Predecessor ADSL.RANDDT
ASEQAnalysis Sequence Numberinteger8Sequence number of the records of the RECIST 1.1 target lesion and sum of diameters data of a subject, by PARAMCD, AVISITN and TRSEQ.
PARAMCDParameter CodetextLDIAMn and NLDIAMn for target lesion n's longest diameter and short axis (TR of the investigator, RECIST 1.1), and SDIAM for the sum of diameters.
PARAMParametertextThe parameter's name, set with PARAMCD by the RECIST 1.1 tumor measurement derivation, e.g. Target Lesions Sum of Diameters by Investigator.
PARCAT1Parameter Category 1textTarget Lesion(s) (RECIST 1.1 tumor measurements).
PARCAT2Parameter Category 2textInvestigator (the evaluator of the RECIST 1.1 tumor measurements).
PARCAT3Parameter Category 3textRECIST 1.1 (the criteria of the target lesion measurements).
AVALAnalysis Valuefloat8The lesion's measurement (TR.TRSTRESN); for SDIAM the sum of diameters: the longest diameter of each non-nodal target lesion plus the short axis of each lymph node (RECIST 1.1).
BASEBaseline Valuefloat8The RECIST 1.1 sum of diameters of the target lesions before treatment: the last sum on or before day 1; changes and the nadir are measured against it.
CHGChange from Baselinefloat8AVAL minus BASE for the sum of diameters (RECIST 1.1 target lesions).
PCHGPercent Change from Baselinefloat8Percent change of the sum of diameters from baseline: (AVAL - BASE) / BASE * 100 (RECIST 1.1 target lesions).
NADIRNadirfloat8The smallest analysed sum of diameters on an earlier day (RECIST 1.1 nadir).
CHGNADChange from Nadirfloat8AVAL minus NADIR for the sum of diameters (RECIST 1.1 nadir).
PCHGNADPercent Change from Nadirfloat8Percent change of the sum of diameters from the nadir (RECIST 1.1).
ADTAnalysis Dateinteger8TR.TRDTC converted, a missing day imputed to the first of the month; for SDIAM the earliest of the lesions' dates (RECIST 1.1 tumor measurements).
ADTFAnalysis Date Imputation FlagtextD when the day of the RECIST 1.1 measurement date was imputed.
ADYAnalysis Relative Dayinteger8Days from randomization to ADT, no day 0 (RECIST 1.1 tumor measurements).
AVISITAnalysis VisittextBASELINE for the screening measurements, else TR.VISIT (RECIST 1.1 tumor measurements).
AVISITNAnalysis Visit (N)float80 for baseline, else TR.VISITNUM (RECIST 1.1 tumor measurements).
ABLFLBaseline Record FlagtextY for the last sum of diameters on or before day 1 (RECIST 1.1 baseline).
ANL01FLAnalysis Flag 01textY for a measured lesion; for SDIAM, Y when every target lesion measured at baseline was measured (RECIST 1.1).
ANL02FLAnalysis Flag 02textY for the analysed sum of diameters after randomization with the smallest percent change (RECIST 1.1 best response).
ANL03FLAnalysis Flag 03textY for the analysed sums of diameters and PD dates before the first PD (RECIST 1.1).
ANL04FLAnalysis Flag 04textY for the analysed sums of diameters and PD dates (RECIST 1.1).
PDFLProgressive Disease FlagtextY when the overall response of the same date is PD (RECIST 1.1 tumor measurements).
TULOCLocation of the TumortextPredecessor TU.TULOC
TULOCGR1Tumor Location Group 1textNODAL for a lymph node, else NON-NODAL (RECIST 1.1 short axis or longest diameter).
LSEXPLesions ExpectedtextThe target lesions measured at baseline (RECIST 1.1 sum of diameters).
LSASSLesions AssessedtextThe target lesions measured at this assessment (RECIST 1.1 sum of diameters).
TRSEQSequence Numberinteger8Predecessor TR.TRSEQ
TRLNKIDLink IDtextPredecessor TR.TRLNKID
TRTESTCDTumor Assessment Short NametextPredecessor TR.TRTESTCD
TRSTRESNNumeric Result/Finding in Std Unitsfloat8Predecessor TR.TRSTRESN
TREVALEvaluatortextPredecessor TR.TREVAL
VISITVisit NametextPredecessor TR.VISIT
VISITNUMVisit Numberfloat8Predecessor TR.VISITNUM
TRDTCDate/Time of Tumor MeasurementtextPredecessor TR.TRDTC

Program adtr.sas

Version 1, written from Clinwright's patterns, 2026-10-17, checks passed.

/*==== 00-header ====*/
/*----------------------------------------------------------------------------
  Data set : ADTR (Tumor Results Analysis Dataset)
  Reporting effort : CSR
  SDTM     : TR, TU
  ADaM     : ADSL
  The header and the finalize step follow from the specification.
----------------------------------------------------------------------------*/
libname sdtm "/work/sdtm" access=readonly;
libname adam "/work/adam";
options validvarname=upcase nofmterr msglevel=i;

/*==== 10-inputs ====*/
/* The TR records, with the subject's TRTSDT, TRTEDT, SITEID, AGE, SEX, TRT01P, TRT01A, SAFFL, ITTFL, RANDDT from ADSL. */
proc sort data=sdtm.tr(keep=studyid usubjid trseq trgrpid trlnkid trtestcd trstresn treval visitnum visit trdtc) out=work._ds; by usubjid; run;
proc sort data=adam.adsl(keep=usubjid trtsdt trtedt siteid age sex trt01p trt01a saffl ittfl randdt) out=work._adsl; by usubjid; run;
data work._ds;
  merge work._ds(in=_in) work._adsl;
  by usubjid;
  if _in;
run;
/* TULOC (a copy of TU.TULOC): merge it on. */

/*==== 20-parameters ====*/
/* ADTR by RECIST 1.1 (investigator): each target lesion's diameter per assessment (LDIAMn, NLDIAMn) and the sum of
   diameters (SDIAM) with baseline, nadir, changes and analysis flags, as admiralonco derives them (see SKILL.md).
   Inputs: SDTM.TR (TRGRPID TARGET, LDIAM / LPERP), SDTM.TU (TULOC), SDTM.RS (OVRLRESP, for PDFL), ADAM.ADSL (RANDDT).
   Output: WORK.ADTR. */

proc fcmp outlib=work.funcs.recist;
  /* A date from ISO 8601 text, a missing day imputed to the month's first day (a missing month: no date). */
  function dt_first_day(dtc $);
    length part $ 10;
    part = substr(strip(dtc), 1, 10);
    result = .;
    if length(part) = 10 then result = input(part, ?? yymmdd10.);
    else if length(part) = 7 then result = input(cats(part, '-01'), ?? yymmdd10.);
    return(result);
  endsub;
  /* Percent change; missing when the reference is missing or 0. */
  function pct_change(value, reference);
    result = .;
    if not missing(value) and not missing(reference) and reference ne 0 then result = (value - reference) / reference * 100;
    return(result);
  endsub;
run;
options cmplib=work.funcs;

/* ---- One record per lesion and assessment ------------------------------------------------------------------- */
data _tu;
  set sdtm.tu(where=(TUEVAL = 'INVESTIGATOR') keep=USUBJID TULNKID TULOC TUEVAL);
run;
proc sql;
  create table _tr as
  select t.*, a.RANDDT as RANDDT, u.TULOC
  from sdtm.tr as t
       left join adam.adsl as a on a.USUBJID = t.USUBJID
       left join _tu as u on u.USUBJID = t.USUBJID and u.TULNKID = t.TRLNKID
  where t.TREVAL = 'INVESTIGATOR' and t.TRGRPID = 'TARGET' and t.TRTESTCD in ('LDIAM', 'LPERP');
quit;

data _lesion;
  set _tr;
  length TULOCGR1 $ 10 LSEXP LSASS $ 200 AVISIT $ 40 PARAMCD $ 8 PARAM $ 100 PARCAT1 PARCAT2 PARCAT3 $ 40
         ANL01FL ADTF $ 1 _nr $ 8;
  if TULOC = 'LYMPH NODE' then TULOCGR1 = 'NODAL';
  else if not missing(TULOC) then TULOCGR1 = 'NON-NODAL';
  LSEXP = TRLNKID;
  if not missing(TRSTRESN) then LSASS = TRLNKID;
  ADT = dt_first_day(TRDTC);
  if not missing(ADT) and length(strip(TRDTC)) < 10 then ADTF = 'D';
  if not missing(ADT) and not missing(RANDDT) then ADY = ADT - RANDDT + (ADT >= RANDDT);
  if VISIT = 'SCREENING' then do;
    AVISIT = 'BASELINE';
    AVISITN = 0;
  end;
  else do;
    AVISIT = VISIT;
    AVISITN = VISITNUM;
  end;
  _nr = substr(TRLNKID, 3);
  if TRTESTCD = 'LDIAM' then do;
    PARAMCD = cats('LDIAM', _nr);
    PARAM = catx(' ', 'Target Lesion', _nr, 'Analysis Diameter');
  end;
  else do;
    PARAMCD = cats('NLDIAM', _nr);
    PARAM = catx(' ', 'Target Lesion', _nr, 'Analysis Perpendicular');
  end;
  PARCAT1 = 'Target Lesion(s)';
  PARCAT2 = 'Investigator';
  PARCAT3 = 'RECIST 1.1';
  AVAL = TRSTRESN;
  if not missing(AVAL) then ANL01FL = 'Y';
  /* What the sum takes: a non-nodal lesion's longest diameter, a lymph node's short axis. */
  _insum = (TRTESTCD = 'LDIAM' and TULOCGR1 = 'NON-NODAL') or (TRTESTCD = 'LPERP' and TULOCGR1 = 'NODAL');
  format ADT yymmdd10.;
  drop _nr;
run;

/* ---- Sum of diameters per assessment ------------------------------------------------------------------------ */
proc sql;
  create table _sum as
  select STUDYID, USUBJID, RANDDT, AVISIT, AVISITN,
         coalesce(sum(AVAL), 0) as AVAL, min(ADY) as ADY, min(ADT) as ADT format=YYMMDD10.
  from _lesion
  where _insum
  group by STUDYID, USUBJID, RANDDT, AVISIT, AVISITN;
quit;

/* The lesions expected (at baseline) and those assessed (with a value, per assessment), as sorted lists. */
proc sort data=_lesion(where=(_insum)) out=_ls;
  by USUBJID AVISIT TRLNKID;
run;
data _expected(keep=USUBJID LSEXP) _assessed(keep=USUBJID AVISIT LSASS);
  set _ls;
  by USUBJID AVISIT;
  length _list _done $ 200;
  retain _list _done;
  if first.AVISIT then call missing(_list, _done);
  _list = catx(', ', _list, TRLNKID);
  if ANL01FL = 'Y' then _done = catx(', ', _done, TRLNKID);
  if last.AVISIT then do;
    if AVISIT = 'BASELINE' then do;
      LSEXP = _list;
      output _expected;
    end;
    if not missing(_done) then do;
      LSASS = _done;
      output _assessed;
    end;
  end;
run;

/* PDFL: the overall response of that date is PD. */
data _rs(keep=USUBJID ADT PDFL);
  set sdtm.rs(where=(RSTESTCD = 'OVRLRESP' and RSEVAL = 'INVESTIGATOR'));
  length PDFL $ 1;
  ADT = dt_first_day(RSDTC);
  if RSSTRESC = 'PD' then PDFL = 'Y';
  if PDFL = 'Y';
run;
proc sort data=_rs nodupkey;
  by USUBJID ADT;
run;

proc sql;
  create table _sum1 as
  select s.*, e.LSEXP, a.LSASS, r.PDFL
  from _sum as s
       left join _expected as e on e.USUBJID = s.USUBJID
       left join _assessed as a on a.USUBJID = s.USUBJID and a.AVISIT = s.AVISIT
       left join _rs as r on r.USUBJID = s.USUBJID and r.ADT = s.ADT
  order by s.USUBJID, s.ADY;
quit;

/* ANL01FL: every expected lesion assessed. */
data _sum2;
  set _sum1;
  length PARAMCD $ 8 PARAM $ 100 PARCAT1 PARCAT2 PARCAT3 $ 40 ANL01FL ABLFL ANL02FL ANL03FL ANL04FL $ 1;
  PARAMCD = 'SDIAM';
  PARAM = 'Target Lesions Sum of Diameters by Investigator';
  PARCAT1 = 'Target Lesion(s)';
  PARCAT2 = 'Investigator';
  PARCAT3 = 'RECIST 1.1';
  if not missing(LSEXP) and LSEXP = LSASS then ANL01FL = 'Y';
run;

/* ABLFL: the last sum on or before day 1; BASE its value. */
proc sql;
  create table _sum3 as
  select s.*, b.AVAL as BASE, m._bady
  from _sum2 as s
       left join (select USUBJID, max(ADY) as _bady from _sum2 where ADY is not missing and ADY <= 1 group by USUBJID) as m
         on m.USUBJID = s.USUBJID
       left join _sum2 as b on b.USUBJID = s.USUBJID and b.ADY = m._bady
  order by s.USUBJID, s.ADY;
quit;

/* NADIR: the smallest analysed sum (ANL01FL) of an earlier day. Then the changes. */
data _sum4;
  set _sum3;
  by USUBJID ADY;
  retain _before _upto;
  if first.USUBJID then call missing(_before, _upto);
  if first.ADY then _before = _upto;
  if not missing(ADY) then do;
    NADIR = _before;
    if ANL01FL = 'Y' and not missing(AVAL) then _upto = min(_upto, AVAL);
  end;
  if not missing(_bady) and ADY = _bady then ABLFL = 'Y';
  CHG = AVAL - BASE;
  PCHG = pct_change(AVAL, BASE);
  CHGNAD = AVAL - NADIR;
  PCHGNAD = pct_change(AVAL, NADIR);
  drop _before _upto _bady;
run;

/* ANL02FL: of the analysed sums from the first one after randomization on, the one with the smallest percent change.
   ANL03FL: analysed sums and PD dates before the first PD. ANL04FL: analysed sums and PD dates. */
proc sort data=_sum4;
  by USUBJID ADT;
run;
data _sum5;
  set _sum4;
  by USUBJID;
  retain _post;
  if first.USUBJID then _post = 0;
  if not missing(ADT) and not missing(RANDDT) and ADT > RANDDT then _post = 1;
  _cand = (ANL01FL = 'Y' and _post = 1);
run;
proc sql;
  create table _sum6 as
  select s.*, m._best
  from _sum5 as s
       left join (select USUBJID, min(PCHG) as _best from _sum5 where _cand group by USUBJID) as m on m.USUBJID = s.USUBJID
  order by s.USUBJID, s.ADY;
quit;
data _sum;
  set _sum6;
  by USUBJID;
  retain _flagged _pd_seen;
  if first.USUBJID then do;
    _flagged = 0;
    _pd_seen = 0;
  end;
  if _cand and not _flagged and not missing(_best) and PCHG = _best then do;
    ANL02FL = 'Y';
    _flagged = 1;
  end;
  if ANL01FL = 'Y' or PDFL = 'Y' then do;
    if PDFL = 'Y' then _pd_seen = 1;
    if not _pd_seen then ANL03FL = 'Y';
    ANL04FL = 'Y';
  end;
  drop _post _cand _best _flagged _pd_seen;
run;

/* ---- All records, their sequence, and ADSL's variables -------------------------------------------------------- */
data _all;
  set _lesion(drop=_insum) _sum;
run;
proc sort data=_all;
  by STUDYID USUBJID PARAMCD AVISITN TRSEQ;
run;
data _all;
  set _all;
  by STUDYID USUBJID;
  if first.USUBJID then ASEQ = 0;
  ASEQ + 1;
run;
data work._ds;
  merge _all(in=_in drop=RANDDT) adam.adsl;
  by STUDYID USUBJID;
  if _in;
run;

/*==== 89-final ====*/
/* The data set as derived; the finalize step keeps the specification's variables. */
data work._final;
  set work._ds;
run;

/*==== 90-finalize ====*/
/* 90-finalize: from the specification; the variables, their order and attributes are not changed here. */
/* The text variables the specification gives no length: as long as their longest value (at least 1). */
%let _len1 = 1; %let _len2 = 1; %let _len3 = 1; %let _len4 = 1; %let _len5 = 1; %let _len6 = 1; %let _len7 = 1; %let _len8 = 1; %let _len9 = 1; %let _len10 = 1; %let _len11 = 1; %let _len12 = 1; %let _len13 = 1; %let _len14 = 1; %let _len15 = 1; %let _len16 = 1; %let _len17 = 1; %let _len18 = 1; %let _len19 = 1; %let _len20 = 1; %let _len21 = 1; %let _len22 = 1; %let _len23 = 1; %let _len24 = 1; %let _len25 = 1; %let _len26 = 1; %let _len27 = 1; %let _len28 = 1; %let _len29 = 1; %let _len30 = 1;
data _null_;
  length _ren _asg _siz $32767;
  _dsid = open('work._final');
  if varnum(_dsid, 'STUDYID') > 0 then do; _ren = catx(' ', _ren, 'STUDYID=_rz1'); _asg = catx(' ', _asg, 'STUDYID = _rz1;');
    _siz = catx(' ', _siz, '_len1 = max(_len1, lengthn(STUDYID));'); end;
  if varnum(_dsid, 'USUBJID') > 0 then do; _ren = catx(' ', _ren, 'USUBJID=_rz2'); _asg = catx(' ', _asg, 'USUBJID = _rz2;');
    _siz = catx(' ', _siz, '_len2 = max(_len2, lengthn(USUBJID));'); end;
  if varnum(_dsid, 'SITEID') > 0 then do; _ren = catx(' ', _ren, 'SITEID=_rz3'); _asg = catx(' ', _asg, 'SITEID = _rz3;');
    _siz = catx(' ', _siz, '_len3 = max(_len3, lengthn(SITEID));'); end;
  if varnum(_dsid, 'SEX') > 0 then do; _ren = catx(' ', _ren, 'SEX=_rz4'); _asg = catx(' ', _asg, 'SEX = _rz4;');
    _siz = catx(' ', _siz, '_len4 = max(_len4, lengthn(SEX));'); end;
  if varnum(_dsid, 'TRT01P') > 0 then do; _ren = catx(' ', _ren, 'TRT01P=_rz5'); _asg = catx(' ', _asg, 'TRT01P = _rz5;');
    _siz = catx(' ', _siz, '_len5 = max(_len5, lengthn(TRT01P));'); end;
  if varnum(_dsid, 'TRT01A') > 0 then do; _ren = catx(' ', _ren, 'TRT01A=_rz6'); _asg = catx(' ', _asg, 'TRT01A = _rz6;');
    _siz = catx(' ', _siz, '_len6 = max(_len6, lengthn(TRT01A));'); end;
  if varnum(_dsid, 'SAFFL') > 0 then do; _ren = catx(' ', _ren, 'SAFFL=_rz7'); _asg = catx(' ', _asg, 'SAFFL = _rz7;');
    _siz = catx(' ', _siz, '_len7 = max(_len7, lengthn(SAFFL));'); end;
  if varnum(_dsid, 'ITTFL') > 0 then do; _ren = catx(' ', _ren, 'ITTFL=_rz8'); _asg = catx(' ', _asg, 'ITTFL = _rz8;');
    _siz = catx(' ', _siz, '_len8 = max(_len8, lengthn(ITTFL));'); end;
  if varnum(_dsid, 'PARAMCD') > 0 then do; _ren = catx(' ', _ren, 'PARAMCD=_rz9'); _asg = catx(' ', _asg, 'PARAMCD = _rz9;');
    _siz = catx(' ', _siz, '_len9 = max(_len9, lengthn(PARAMCD));'); end;
  if varnum(_dsid, 'PARAM') > 0 then do; _ren = catx(' ', _ren, 'PARAM=_rz10'); _asg = catx(' ', _asg, 'PARAM = _rz10;');
    _siz = catx(' ', _siz, '_len10 = max(_len10, lengthn(PARAM));'); end;
  if varnum(_dsid, 'PARCAT1') > 0 then do; _ren = catx(' ', _ren, 'PARCAT1=_rz11'); _asg = catx(' ', _asg, 'PARCAT1 = _rz11;');
    _siz = catx(' ', _siz, '_len11 = max(_len11, lengthn(PARCAT1));'); end;
  if varnum(_dsid, 'PARCAT2') > 0 then do; _ren = catx(' ', _ren, 'PARCAT2=_rz12'); _asg = catx(' ', _asg, 'PARCAT2 = _rz12;');
    _siz = catx(' ', _siz, '_len12 = max(_len12, lengthn(PARCAT2));'); end;
  if varnum(_dsid, 'PARCAT3') > 0 then do; _ren = catx(' ', _ren, 'PARCAT3=_rz13'); _asg = catx(' ', _asg, 'PARCAT3 = _rz13;');
    _siz = catx(' ', _siz, '_len13 = max(_len13, lengthn(PARCAT3));'); end;
  if varnum(_dsid, 'ADTF') > 0 then do; _ren = catx(' ', _ren, 'ADTF=_rz14'); _asg = catx(' ', _asg, 'ADTF = _rz14;');
    _siz = catx(' ', _siz, '_len14 = max(_len14, lengthn(ADTF));'); end;
  if varnum(_dsid, 'AVISIT') > 0 then do; _ren = catx(' ', _ren, 'AVISIT=_rz15'); _asg = catx(' ', _asg, 'AVISIT = _rz15;');
    _siz = catx(' ', _siz, '_len15 = max(_len15, lengthn(AVISIT));'); end;
  if varnum(_dsid, 'ABLFL') > 0 then do; _ren = catx(' ', _ren, 'ABLFL=_rz16'); _asg = catx(' ', _asg, 'ABLFL = _rz16;');
    _siz = catx(' ', _siz, '_len16 = max(_len16, lengthn(ABLFL));'); end;
  if varnum(_dsid, 'ANL01FL') > 0 then do; _ren = catx(' ', _ren, 'ANL01FL=_rz17'); _asg = catx(' ', _asg, 'ANL01FL = _rz17;');
    _siz = catx(' ', _siz, '_len17 = max(_len17, lengthn(ANL01FL));'); end;
  if varnum(_dsid, 'ANL02FL') > 0 then do; _ren = catx(' ', _ren, 'ANL02FL=_rz18'); _asg = catx(' ', _asg, 'ANL02FL = _rz18;');
    _siz = catx(' ', _siz, '_len18 = max(_len18, lengthn(ANL02FL));'); end;
  if varnum(_dsid, 'ANL03FL') > 0 then do; _ren = catx(' ', _ren, 'ANL03FL=_rz19'); _asg = catx(' ', _asg, 'ANL03FL = _rz19;');
    _siz = catx(' ', _siz, '_len19 = max(_len19, lengthn(ANL03FL));'); end;
  if varnum(_dsid, 'ANL04FL') > 0 then do; _ren = catx(' ', _ren, 'ANL04FL=_rz20'); _asg = catx(' ', _asg, 'ANL04FL = _rz20;');
    _siz = catx(' ', _siz, '_len20 = max(_len20, lengthn(ANL04FL));'); end;
  if varnum(_dsid, 'PDFL') > 0 then do; _ren = catx(' ', _ren, 'PDFL=_rz21'); _asg = catx(' ', _asg, 'PDFL = _rz21;');
    _siz = catx(' ', _siz, '_len21 = max(_len21, lengthn(PDFL));'); end;
  if varnum(_dsid, 'TULOC') > 0 then do; _ren = catx(' ', _ren, 'TULOC=_rz22'); _asg = catx(' ', _asg, 'TULOC = _rz22;');
    _siz = catx(' ', _siz, '_len22 = max(_len22, lengthn(TULOC));'); end;
  if varnum(_dsid, 'TULOCGR1') > 0 then do; _ren = catx(' ', _ren, 'TULOCGR1=_rz23'); _asg = catx(' ', _asg, 'TULOCGR1 = _rz23;');
    _siz = catx(' ', _siz, '_len23 = max(_len23, lengthn(TULOCGR1));'); end;
  if varnum(_dsid, 'LSEXP') > 0 then do; _ren = catx(' ', _ren, 'LSEXP=_rz24'); _asg = catx(' ', _asg, 'LSEXP = _rz24;');
    _siz = catx(' ', _siz, '_len24 = max(_len24, lengthn(LSEXP));'); end;
  if varnum(_dsid, 'LSASS') > 0 then do; _ren = catx(' ', _ren, 'LSASS=_rz25'); _asg = catx(' ', _asg, 'LSASS = _rz25;');
    _siz = catx(' ', _siz, '_len25 = max(_len25, lengthn(LSASS));'); end;
  if varnum(_dsid, 'TRLNKID') > 0 then do; _ren = catx(' ', _ren, 'TRLNKID=_rz26'); _asg = catx(' ', _asg, 'TRLNKID = _rz26;');
    _siz = catx(' ', _siz, '_len26 = max(_len26, lengthn(TRLNKID));'); end;
  if varnum(_dsid, 'TRTESTCD') > 0 then do; _ren = catx(' ', _ren, 'TRTESTCD=_rz27'); _asg = catx(' ', _asg, 'TRTESTCD = _rz27;');
    _siz = catx(' ', _siz, '_len27 = max(_len27, lengthn(TRTESTCD));'); end;
  if varnum(_dsid, 'TREVAL') > 0 then do; _ren = catx(' ', _ren, 'TREVAL=_rz28'); _asg = catx(' ', _asg, 'TREVAL = _rz28;');
    _siz = catx(' ', _siz, '_len28 = max(_len28, lengthn(TREVAL));'); end;
  if varnum(_dsid, 'VISIT') > 0 then do; _ren = catx(' ', _ren, 'VISIT=_rz29'); _asg = catx(' ', _asg, 'VISIT = _rz29;');
    _siz = catx(' ', _siz, '_len29 = max(_len29, lengthn(VISIT));'); end;
  if varnum(_dsid, 'TRDTC') > 0 then do; _ren = catx(' ', _ren, 'TRDTC=_rz30'); _asg = catx(' ', _asg, 'TRDTC = _rz30;');
    _siz = catx(' ', _siz, '_len30 = max(_len30, lengthn(TRDTC));'); end;
  _rc = close(_dsid);
  if _ren ne '' then _ren = cats('(rename=(', _ren, '))');
  call symputx('_ren', _ren);
  call symputx('_asg', _asg);
  call symputx('_siz', _siz);
run;
data _null_;
  set work._final end=_end;
  retain _len1 1 _len2 1 _len3 1 _len4 1 _len5 1 _len6 1 _len7 1 _len8 1 _len9 1 _len10 1 _len11 1 _len12 1 _len13 1 _len14 1 _len15 1 _len16 1 _len17 1 _len18 1 _len19 1 _len20 1 _len21 1 _len22 1 _len23 1 _len24 1 _len25 1 _len26 1 _len27 1 _len28 1 _len29 1 _len30 1;
  &_siz
  if _end then do;
    call symputx('_len1', _len1);
    call symputx('_len2', _len2);
    call symputx('_len3', _len3);
    call symputx('_len4', _len4);
    call symputx('_len5', _len5);
    call symputx('_len6', _len6);
    call symputx('_len7', _len7);
    call symputx('_len8', _len8);
    call symputx('_len9', _len9);
    call symputx('_len10', _len10);
    call symputx('_len11', _len11);
    call symputx('_len12', _len12);
    call symputx('_len13', _len13);
    call symputx('_len14', _len14);
    call symputx('_len15', _len15);
    call symputx('_len16', _len16);
    call symputx('_len17', _len17);
    call symputx('_len18', _len18);
    call symputx('_len19', _len19);
    call symputx('_len20', _len20);
    call symputx('_len21', _len21);
    call symputx('_len22', _len22);
    call symputx('_len23', _len23);
    call symputx('_len24', _len24);
    call symputx('_len25', _len25);
    call symputx('_len26', _len26);
    call symputx('_len27', _len27);
    call symputx('_len28', _len28);
    call symputx('_len29', _len29);
    call symputx('_len30', _len30);
  end;
run;
data adam.adtr(label="Tumor Results Analysis Dataset");
  attrib
    STUDYID  length=$&_len1 label="Study Identifier"
    USUBJID  length=$&_len2 label="Unique Subject Identifier"
    SITEID   length=$&_len3 label="Study Site Identifier"
    AGE      length=8 label="Age"
    SEX      length=$&_len4 label="Sex"
    TRT01P   length=$&_len5 label="Planned Treatment for Period 01"
    TRT01A   length=$&_len6 label="Actual Treatment for Period 01"
    SAFFL    length=$&_len7 label="Safety Population Flag"
    ITTFL    length=$&_len8 label="Intent-To-Treat Population Flag"
    RANDDT   length=8 label="Date of Randomization" format=DATE9.
    ASEQ     length=8 label="Analysis Sequence Number"
    PARAMCD  length=$&_len9 label="Parameter Code"
    PARAM    length=$&_len10 label="Parameter"
    PARCAT1  length=$&_len11 label="Parameter Category 1"
    PARCAT2  length=$&_len12 label="Parameter Category 2"
    PARCAT3  length=$&_len13 label="Parameter Category 3"
    AVAL     length=8 label="Analysis Value"
    BASE     length=8 label="Baseline Value"
    CHG      length=8 label="Change from Baseline"
    PCHG     length=8 label="Percent Change from Baseline"
    NADIR    length=8 label="Nadir"
    CHGNAD   length=8 label="Change from Nadir"
    PCHGNAD  length=8 label="Percent Change from Nadir"
    ADT      length=8 label="Analysis Date" format=DATE9.
    ADTF     length=$&_len14 label="Analysis Date Imputation Flag"
    ADY      length=8 label="Analysis Relative Day"
    AVISIT   length=$&_len15 label="Analysis Visit"
    AVISITN  length=8 label="Analysis Visit (N)"
    ABLFL    length=$&_len16 label="Baseline Record Flag"
    ANL01FL  length=$&_len17 label="Analysis Flag 01"
    ANL02FL  length=$&_len18 label="Analysis Flag 02"
    ANL03FL  length=$&_len19 label="Analysis Flag 03"
    ANL04FL  length=$&_len20 label="Analysis Flag 04"
    PDFL     length=$&_len21 label="Progressive Disease Flag"
    TULOC    length=$&_len22 label="Location of the Tumor"
    TULOCGR1 length=$&_len23 label="Tumor Location Group 1"
    LSEXP    length=$&_len24 label="Lesions Expected"
    LSASS    length=$&_len25 label="Lesions Assessed"
    TRSEQ    length=8 label="Sequence Number"
    TRLNKID  length=$&_len26 label="Link ID"
    TRTESTCD length=$&_len27 label="Tumor Assessment Short Name"
    TRSTRESN length=8 label="Numeric Result/Finding in Std Units"
    TREVAL   length=$&_len28 label="Evaluator"
    VISIT    length=$&_len29 label="Visit Name"
    VISITNUM length=8 label="Visit Number"
    TRDTC    length=$&_len30 label="Date/Time of Tumor Measurement"
  ;
  set work._final&_ren;
  &_asg
  keep STUDYID USUBJID SITEID AGE SEX TRT01P TRT01A SAFFL ITTFL RANDDT ASEQ PARAMCD PARAM PARCAT1 PARCAT2 PARCAT3 AVAL BASE CHG PCHG NADIR CHGNAD PCHGNAD ADT ADTF ADY AVISIT AVISITN ABLFL ANL01FL ANL02FL ANL03FL ANL04FL PDFL TULOC TULOCGR1 LSEXP LSASS TRSEQ TRLNKID TRTESTCD TRSTRESN TREVAL VISIT VISITNUM TRDTC;
run;
proc sort data=adam.adtr; by STUDYID USUBJID PARAMCD AVISITN; run;

Data (first 20 of 11,858 records, simulated)

STUDYIDUSUBJIDSITEIDAGESEXTRT01PTRT01ASAFFLITTFLRANDDTASEQPARAMCDPARAMPARCAT1PARCAT2PARCAT3AVALBASECHGPCHGNADIRCHGNADPCHGNADADTADTFADYAVISITAVISITNABLFLANL01FLANL02FLANL03FLANL04FLPDFLTULOCTULOCGR1LSEXPLSASSTRSEQTRLNKIDTRTESTCDTRSTRESNTREVALVISITVISITNUMTRDTC
ONCO-EXONCO-EX-70100270157FStandard of CareStandard of CareYY2022-02-111LDIAM1Target Lesion 1 Analysis DiameterTarget Lesion(s)InvestigatorRECIST 1.1622022-02-09-2BASELINE0YLIVERNON-NODALT01T0125T01LDIAM62INVESTIGATORSCREENING12022-02-09
ONCO-EXONCO-EX-70100270157FStandard of CareStandard of CareYY2022-02-112LDIAM1Target Lesion 1 Analysis DiameterTarget Lesion(s)InvestigatorRECIST 1.1412022-03-2341WEEK 64YLIVERNON-NODALT01T0126T01LDIAM41INVESTIGATORWEEK 642022-03-23
ONCO-EXONCO-EX-70100270157FStandard of CareStandard of CareYY2022-02-113LDIAM1Target Lesion 1 Analysis DiameterTarget Lesion(s)InvestigatorRECIST 1.1412022-05-1190WEEK 126YLIVERNON-NODALT01T0127T01LDIAM41INVESTIGATORWEEK 1262022-05-11
ONCO-EXONCO-EX-70100270157FStandard of CareStandard of CareYY2022-02-114LDIAM1Target Lesion 1 Analysis DiameterTarget Lesion(s)InvestigatorRECIST 1.1412022-06-23133WEEK 188YLIVERNON-NODALT01T0128T01LDIAM41INVESTIGATORWEEK 1882022-06-23
ONCO-EXONCO-EX-70100270157FStandard of CareStandard of CareYY2022-02-115LDIAM1Target Lesion 1 Analysis DiameterTarget Lesion(s)InvestigatorRECIST 1.1412022-08-02173WEEK 2410YLIVERNON-NODALT01T0129T01LDIAM41INVESTIGATORWEEK 24102022-08-02
ONCO-EXONCO-EX-70100270157FStandard of CareStandard of CareYY2022-02-116LDIAM1Target Lesion 1 Analysis DiameterTarget Lesion(s)InvestigatorRECIST 1.1412022-09-13215WEEK 3012YLIVERNON-NODALT01T0130T01LDIAM41INVESTIGATORWEEK 30122022-09-13
ONCO-EXONCO-EX-70100270157FStandard of CareStandard of CareYY2022-02-117LDIAM1Target Lesion 1 Analysis DiameterTarget Lesion(s)InvestigatorRECIST 1.1412022-10-24256WEEK 3614YLIVERNON-NODALT01T0131T01LDIAM41INVESTIGATORWEEK 36142022-10-24
ONCO-EXONCO-EX-70100270157FStandard of CareStandard of CareYY2022-02-118LDIAM1Target Lesion 1 Analysis DiameterTarget Lesion(s)InvestigatorRECIST 1.1412022-11-29292WEEK 4216YLIVERNON-NODALT01T0132T01LDIAM41INVESTIGATORWEEK 42162022-11-29
ONCO-EXONCO-EX-70100270157FStandard of CareStandard of CareYY2022-02-119LDIAM2Target Lesion 2 Analysis DiameterTarget Lesion(s)InvestigatorRECIST 1.1282022-02-09-2BASELINE0YKIDNEYNON-NODALT02T0241T02LDIAM28INVESTIGATORSCREENING12022-02-09
ONCO-EXONCO-EX-70100270157FStandard of CareStandard of CareYY2022-02-1110LDIAM2Target Lesion 2 Analysis DiameterTarget Lesion(s)InvestigatorRECIST 1.1182022-03-2341WEEK 64YKIDNEYNON-NODALT02T0242T02LDIAM18INVESTIGATORWEEK 642022-03-23
ONCO-EXONCO-EX-70100270157FStandard of CareStandard of CareYY2022-02-1111LDIAM2Target Lesion 2 Analysis DiameterTarget Lesion(s)InvestigatorRECIST 1.1182022-05-1190WEEK 126YKIDNEYNON-NODALT02T0243T02LDIAM18INVESTIGATORWEEK 1262022-05-11
ONCO-EXONCO-EX-70100270157FStandard of CareStandard of CareYY2022-02-1112LDIAM2Target Lesion 2 Analysis DiameterTarget Lesion(s)InvestigatorRECIST 1.1182022-06-23133WEEK 188YKIDNEYNON-NODALT02T0244T02LDIAM18INVESTIGATORWEEK 1882022-06-23
ONCO-EXONCO-EX-70100270157FStandard of CareStandard of CareYY2022-02-1113LDIAM2Target Lesion 2 Analysis DiameterTarget Lesion(s)InvestigatorRECIST 1.1182022-08-02173WEEK 2410YKIDNEYNON-NODALT02T0245T02LDIAM18INVESTIGATORWEEK 24102022-08-02
ONCO-EXONCO-EX-70100270157FStandard of CareStandard of CareYY2022-02-1114LDIAM2Target Lesion 2 Analysis DiameterTarget Lesion(s)InvestigatorRECIST 1.1182022-09-13215WEEK 3012YKIDNEYNON-NODALT02T0246T02LDIAM18INVESTIGATORWEEK 30122022-09-13
ONCO-EXONCO-EX-70100270157FStandard of CareStandard of CareYY2022-02-1115LDIAM2Target Lesion 2 Analysis DiameterTarget Lesion(s)InvestigatorRECIST 1.1182022-10-24256WEEK 3614YKIDNEYNON-NODALT02T0247T02LDIAM18INVESTIGATORWEEK 36142022-10-24
ONCO-EXONCO-EX-70100270157FStandard of CareStandard of CareYY2022-02-1116LDIAM2Target Lesion 2 Analysis DiameterTarget Lesion(s)InvestigatorRECIST 1.1182022-11-29292WEEK 4216YKIDNEYNON-NODALT02T0248T02LDIAM18INVESTIGATORWEEK 42162022-11-29
ONCO-EXONCO-EX-70100270157FStandard of CareStandard of CareYY2022-02-1117LDIAM3Target Lesion 3 Analysis DiameterTarget Lesion(s)InvestigatorRECIST 1.1712022-02-09-2BASELINE0YLIVERNON-NODALT03T0357T03LDIAM71INVESTIGATORSCREENING12022-02-09
ONCO-EXONCO-EX-70100270157FStandard of CareStandard of CareYY2022-02-1118LDIAM3Target Lesion 3 Analysis DiameterTarget Lesion(s)InvestigatorRECIST 1.1392022-03-2341WEEK 64YLIVERNON-NODALT03T0358T03LDIAM39INVESTIGATORWEEK 642022-03-23
ONCO-EXONCO-EX-70100270157FStandard of CareStandard of CareYY2022-02-1119LDIAM3Target Lesion 3 Analysis DiameterTarget Lesion(s)InvestigatorRECIST 1.1392022-05-1190WEEK 126YLIVERNON-NODALT03T0359T03LDIAM39INVESTIGATORWEEK 1262022-05-11
ONCO-EXONCO-EX-70100270157FStandard of CareStandard of CareYY2022-02-1120LDIAM3Target Lesion 3 Analysis DiameterTarget Lesion(s)InvestigatorRECIST 1.1392022-06-23133WEEK 188YLIVERNON-NODALT03T0360T03LDIAM39INVESTIGATORWEEK 1882022-06-23