Clinical SAS Technical Case Study: From Raw Clinical Trial Data to Regulatory-Ready Analysis
  • by Handson
  • August 17, 2026
Clinical SAS Technical Case Study: From Raw Clinical Trial Data to Regulatory-Ready Analysis

Company: NovaCure Pharmaceuticals Ltd.
Study: NC-201-301
Phase: Phase III
Therapeutic Area: Oncology
Indication: Advanced Metastatic Colorectal Cancer
Treatment: NC-201 + Standard of Care vs Placebo + Standard of Care
Programming Environment: SAS 9.4
Data Standards: CDISC SDTM and ADaM
Primary Analysis: Efficacy and Safety
Case Study Type: Fictionalized technical project using simulated clinical-trial data

The Business Problem

At 6:30 PM on a Thursday, the Clinical Data Management team at NovaCure Pharmaceuticals Ltd. released the final database snapshot for one of the company's most important clinical programs.

The study was NC-201-301, a randomized, double-blind, placebo-controlled Phase III trial evaluating NC-201 in patients with advanced metastatic colorectal cancer.

The database was locked.

The clinical team was waiting.

The biostatisticians were preparing the statistical analysis.

Regulatory submission activities were approaching.

And the Clinical Programming team had one critical responsibility:

Convert the locked clinical data into standardized, analysis-ready datasets and produce the statistical outputs required for the primary study report.

The raw data looked straightforward.

It wasn't.

The programming team discovered inconsistencies in treatment assignments, partial dates, duplicate laboratory records, adverse-event terminology and several derivation requirements that could materially affect the analysis.

The project became a practical demonstration of why clinical programming is not simply about writing SAS code.

It is about understanding data, clinical meaning, statistical requirements, CDISC standards and validation at the same time.

1. The Clinical Trial

NovaCure Pharmaceuticals designed NC-201-301 to evaluate whether NC-201 could improve progression-free survival compared with placebo when administered alongside standard-of-care therapy.

The study randomized 612 subjects across 86 clinical sites.

Study Design

Parameter Study Detail
Study NC-201-301
Phase III
Design Randomized, double-blind, placebo-controlled
Subjects randomized 612
Treatment arms NC-201 + SoC / Placebo + SoC
Primary endpoint Progression-Free Survival
Secondary endpoint Overall Survival
Safety assessment Adverse Events, Laboratory Data, Vital Signs
Database status Locked
Programming standard SAS 9.4
Data standards SDTM / ADaM

The programming team was responsible for transforming the source data into the required standardized and analysis datasets and producing the planned TLFs.

2. The Raw Data Arrives

The first programming package contained raw datasets extracted from the clinical database.

The initial directory looked something like this:

/raw_data
    dm_raw.sas7bdat
    ae_raw.sas7bdat
    cm_raw.sas7bdat
    ex_raw.sas7bdat
    lb_raw.sas7bdat
    vs_raw.sas7bdat
    ds_raw.sas7bdat
    tumor_raw.sas7bdat

The team also received:

/specifications
    SDTM_mapping_spec.xlsx
    ADaM_spec.xlsx
    TLF_shells.xlsx
    SAP.pdf
    CRF.pdf

This is an important distinction.

The programmer does not simply open the raw dataset and start coding.

Before programming begins, the team needs to understand:

What was collected?

What does each variable mean?

What is the target standard?

What does the Statistical Analysis Plan require?

What population should be analyzed?

What derivations are required?

The documentation drives the programming.

3. Step One: Understanding the Raw Data

The programming team began with a basic SAS assessment.

proc contents data=raw.dm_raw;
run;

proc contents data=raw.ae_raw;
run;

proc contents data=raw.lb_raw;
run;

They then reviewed frequencies and missing values.

proc freq data=raw.dm_raw;
    tables sex race country / missing;
run;

proc freq data=raw.ae_raw;
    tables aeterm aeser aeout / missing;
run;

For continuous laboratory variables:

proc means data=raw.lb_raw n nmiss min max mean std;
    var lbvalue;
run;

This first profiling exercise immediately uncovered several issues.

Finding 1: Treatment Assignment

The raw treatment variable contained:

NC-201
NC-201
NC201
Placebo
PLACEBO

The values were clinically equivalent in meaning but technically inconsistent.

Finding 2: Partial Dates

Some adverse-event dates were recorded as:

2025-06
2025

rather than complete ISO dates.

Finding 3: Duplicate Laboratory Records

Several subjects had duplicate laboratory observations for the same visit and test.

Finding 4: Missing Baseline Indicators

The raw data did not contain a ready-made baseline flag.

The team therefore had to derive it according to the statistical analysis specifications.

4. SDTM Programming Begins

The first major deliverable was the SDTM layer.

The programming team started with the DM domain.

The raw demographic data contained variables such as:

SUBJECT_ID
SITE
SEX
RACE
COUNTRY
BRTHDAT
RANDOMIZED_TREATMENT

The SDTM mapping specification required standardized variables including:

STUDYID
DOMAIN
USUBJID
SUBJID
SITEID
SEX
RACE
COUNTRY
ARM
ACTARM
RFSTDTC
RFENDTC

5. Creating the DM Domain

A simplified example of the SAS programming logic was:

data sdtm.dm;
    set raw.dm_raw;

    length STUDYID $20 DOMAIN $2 USUBJID $30;

    STUDYID = "NC-201-301";
    DOMAIN   = "DM";

    SUBJID   = strip(subject_id);
    SITEID   = strip(site);

    USUBJID  = cats(STUDYID, "-", SUBJID);

    SEX      = upcase(strip(sex));
    RACE     = strip(race);
    COUNTRY  = upcase(strip(country));

    ARM = case
          when upcase(randomized_treatment) = "NC-201" 
               then "NC-201 + Standard of Care"
          when upcase(randomized_treatment) = "PLACEBO" 
               then "Placebo + Standard of Care"
          else ""
          end;

    keep STUDYID DOMAIN USUBJID SUBJID SITEID
         SEX RACE COUNTRY ARM;
run;

The actual implementation would follow the study-specific mapping specifications and applicable SDTM implementation guidance.

The important point is that the programmer wasn't merely renaming variables.

The programmer was applying business rules and clinical specifications.

6. The First Major Programming Challenge

During validation, the team discovered that 11 subjects had a mismatch between randomized treatment and actual treatment received.

For example:

USUBJID Randomized Actual Treatment
NC-201-301-00123 NC-201 NC-201
NC-201-301-00187 NC-201 Placebo
NC-201-301-00341 Placebo NC-201

This created an important distinction.

The analysis could require:

  • Planned treatment

  • Randomized treatment

  • Actual treatment

These concepts are not interchangeable.

The team went back to the Statistical Analysis Plan and dataset specifications before making any programming decision.

This is where clinical programming differs from ordinary data manipulation.

The programmer cannot simply decide which variable "looks right."

The specification and statistical methodology determine the correct derivation.


7. Handling Partial Dates

Another challenge involved adverse-event dates.

Suppose the raw data contained:

AE Start Date = 2025-07

The programmer cannot simply assume:

2025-07-01

because that would create information that was never actually collected.

Instead, partial dates need to be represented appropriately according to the study's specifications and data standards.

A simplified ISO conversion might preserve the known precision:

if length(aestdt_raw)=10 then
    aestdtc = aestdt_raw;
else if length(aestdt_raw)=7 then
    aestdtc = aestdt_raw;
else if length(aestdt_raw)=4 then
    aestdtc = aestdt_raw;

The exact treatment of partial dates for analysis variables would then follow the SAP and ADaM specifications.

This distinction is critical:

SDTM representation and statistical analysis derivation are not necessarily the same thing.

8. Building the AE Domain

The Adverse Events domain was another major component.

The raw dataset contained:

SUBJECT_ID
AE_TERM
START_DATE
END_DATE
SERIOUS
SEVERITY
OUTCOME
RELATIONSHIP

The target SDTM domain required standardized variables.

A simplified programming structure could look like:

data sdtm.ae;
    set raw.ae_raw;

    length STUDYID $20 DOMAIN $2 USUBJID $30;

    STUDYID = "NC-201-301";
    DOMAIN   = "AE";

    USUBJID  = cats(STUDYID, "-", strip(subject_id));

    AETERM   = strip(ae_term);
    AESER    = upcase(strip(serious));
    AESEV    = strip(severity);
    AEOUT    = strip(outcome);

    AESTDTC  = start_date;
    AEENDTC  = end_date;

    keep STUDYID DOMAIN USUBJID
         AETERM AESER AESEV AEOUT
         AESTDTC AEENDTC;
run;

Again, the production program would be driven by the study's approved mapping specifications, controlled terminology and validation requirements.

9. From SDTM to ADaM

Once the SDTM datasets were completed and validated, the project moved into the analysis layer.

The first major analysis dataset was:

ADSL — Subject-Level Analysis Dataset

The objective was to create one record per subject containing the key variables required for analysis.

The ADSL specification included variables such as:

STUDYID
USUBJID
SUBJID
SITEID
AGE
SEX
RACE
TRT01P
TRT01A
SAFFL
ITTFL
FASFL
RANDDT
TRTSDT
TRTEDT

The programmer created ADSL by integrating information from multiple SDTM domains and other approved source datasets.

10. Deriving the Safety Population

The Statistical Analysis Plan defined the Safety Population as subjects who received at least one dose of study treatment.

The programming team therefore needed to determine treatment exposure from the EX domain.

Conceptually:

proc sql;
    create table exposure as
    select usubjid,
           min(input(exstdtc,yymmdd10.)) as first_dose format=date9.
    from sdtm.ex
    where not missing(exstdtc)
    group by usubjid;
quit;

The ADSL derivation could then use the exposure information to assign the safety flag.

if not missing(first_dose) then SAFFL="Y";
else SAFFL="N";

But even this apparently simple derivation requires careful consideration.

What constitutes exposure?

What if the dose was recorded but subsequently invalidated?

What if the subject received placebo?

What if treatment administration was partially recorded?

The answers come from the study specifications and SAP—not from the programmer's assumptions.


11. The Baseline Problem

One of the most common real-world programming challenges is determining the correct baseline value.

Suppose a subject has laboratory results:

Date Hemoglobin
Day -14 10.8
Day -7 11.1
Day 1 10.9
Day 8 11.5

Which value is baseline?

The answer isn't automatically "the first value."

The study specification may define baseline as:

The last non-missing assessment collected before the first dose of study treatment.

The programmer therefore needed to derive baseline according to the protocol-defined rule.

A simplified approach might involve sorting by subject, test and date and selecting the appropriate observation.

proc sort data=sdtm.lb out=lb_sorted;
    by usubjid lbtestcd lbdt;
run;

The final derivation would incorporate the study-specific treatment start date and baseline window.

This is where SAS programming meets statistical methodology.

12. Creating ADAE

The next major analysis dataset was ADAE, the analysis dataset for adverse events.

ADAE needed to support questions such as:

  • How many subjects experienced at least one AE?

  • How many experienced serious AEs?

  • How many experienced Grade 3 or higher AEs?

  • How many experienced treatment-related AEs?

  • Which preferred terms were most common?

  • Which system organ classes were most affected?

The dataset therefore incorporated analysis variables derived from SDTM AE data and treatment dates.

For example:

USUBJID
TRT01A
SAFFL
AEREL
AESER
AESEV
AEBODSYS
AEDECOD
ASTDT
AENDT
ASTDY
AENDY

13. The Treatment-Emergent AE Derivation

One of the most important derivations was the treatment-emergent adverse event flag.

The study specification defined a treatment-emergent AE according to the protocol/SAP-defined relationship between the AE start date and treatment exposure.

A simplified conceptual derivation might be:

if not missing(ASTDT) and not missing(TRTSDT) then do;

    if ASTDT >= TRTSDT then
        TRTEMFL = "Y";

end;

However, real-world studies may have additional rules involving treatment periods, partial dates, prior events and post-treatment windows.

Therefore, the production derivation must always follow the approved specification.

14. Creating ADLB

The laboratory analysis dataset required another layer of derivations.

The raw laboratory data contained:

SUBJECT
TEST
RESULT
UNIT
REFERENCE_LOW
REFERENCE_HIGH
DATE

The analysis dataset needed to support:

  • Baseline values

  • Post-baseline values

  • Change from baseline

  • Percent change

  • Normal/abnormal classification

  • Shift tables

  • Potentially clinically significant abnormalities

A simplified derivation of change might be:

CHG = AVAL - BASE;

and percent change:

if BASE ne 0 then
    PCHG = ((AVAL - BASE) / BASE) * 100;

The programmer then validated these derivations against the approved specifications.

15. From Analysis Datasets to TLFs

Now came the deliverables the clinical team was waiting for.

Tables, Listings and Figures.

The programming team had to reproduce the outputs defined in the Statistical Analysis Plan.

Examples included:

Table 14.1.1

Subject Disposition

Table 14.2.1

Demographic and Baseline Characteristics

Table 14.3.1

Overall Summary of Adverse Events

Table 14.3.2

Treatment-Emergent Adverse Events by System Organ Class and Preferred Term

Table 14.3.3

Serious Adverse Events

Figure 14.2.1

Kaplan-Meier Curve for Progression-Free Survival

Listing 16.2.7

Serious Adverse Events

This is where the programming team transformed datasets into information that clinicians and statisticians could interpret.

16. Example: Safety Table Programming

Suppose the safety population consisted of:

Treatment Subjects
NC-201 306
Placebo 298

The programmer might create an AE summary using:

proc freq data=adam.adae;
    tables TRT01A*AEDECOD / norow nocol nopercent;
    where SAFFL="Y" and TRTEMFL="Y";
run;

But a production-quality table requires much more than a PROC FREQ.

The programmer must account for:

  • Subject-level counting

  • Multiple occurrences of the same AE

  • Severity

  • Seriousness

  • Treatment relationship

  • System Organ Class

  • Preferred Term

  • Treatment groups

  • Denominators

  • Missing values

  • Table formatting

For example, if one patient experienced the same adverse event five times, the table may need to count that patient once, depending on the table's statistical rules.

That requires careful programming.

17. The TLF Quality-Control Problem

The first production run generated the following result:

NC-201 treatment arm: 184 subjects with at least one TEAE

But the independent QC program produced:

NC-201 treatment arm: 186 subjects with at least one TEAE

Two subjects were missing.

The team stopped the production process.

They did not simply change the number.

They investigated.


18. Root-Cause Analysis

The programmers compared:

Production Dataset

versus

Independent QC Dataset

They used SAS comparison procedures.

proc compare
    base=prod.adae
    compare=qc.adae
    listall;
run;

The difference came from two subjects with partially recorded AE start dates.

The production program had excluded the records because the date could not be completely derived.

The QC program had retained them based on the study-specific partial-date rules.

The team reviewed the specifications.

The QC interpretation was correct.

The production derivation was updated.

The datasets were regenerated.

The table was rerun.

The counts matched.

This was a small programming discrepancy.

But in a regulated environment, it was a serious quality issue.

19. Why Independent Programming Matters

This is one of the most important lessons from the project.

Clinical programming cannot rely on:

"The program ran without errors."

A SAS log can be clean while the result is wrong.

Therefore, the project used independent QC.

The workflow was:

Specification
      ↓
Production Programming
      ↓
Analysis Dataset
      ↓
Independent QC Programming
      ↓
Comparison
      ↓
Discrepancy Investigation
      ↓
Resolution
      ↓
Final Dataset
      ↓
Final TLF

This creates an additional layer of confidence in the results.

20. The Kaplan-Meier Challenge

The primary endpoint was progression-free survival.

The statistical team required a Kaplan-Meier analysis comparing the two treatment arms.

The analysis dataset needed variables such as:

USUBJID
TRT01A
AVAL
CNSR

where:

  • AVAL represented analysis time

  • CNSR represented the censoring indicator

A simplified SAS implementation could use:

proc lifetest data=adam.adtte
              plots=survival;
    time AVAL*CNSR(1);
    strata TRT01A;
run;

The actual production analysis would follow the exact statistical methodology defined in the SAP, including time origin, event definition, censoring rules, analysis populations and other study-specific requirements.

This illustrates another important point:

The Clinical SAS Programmer is implementing statistical methodology—not inventing it.

The Statistical Analysis Plan provides the analytical framework.

The programmer translates that framework into reproducible code.

21. The Final Data Flow

After several rounds of programming, QC and review, the final architecture looked like this:

                 RAW CLINICAL DATA
                        |
                        v
              +-------------------+
              | Data Review &     |
              | Profiling         |
              +-------------------+
                        |
                        v
                 SDTM DATASETS
                        |
          +-------------+-------------+
          |             |             |
          v             v             v
         DM            AE            LB
          |             |             |
          +-------------+-------------+
                        |
                        v
                 ADaM DATASETS
                        |
          +-------------+-------------+
          |             |             |
          v             v             v
        ADSL          ADAE          ADLB
                        |
                        v
                  TLF PROGRAMS
                        |
          +-------------+-------------+
          |             |             |
          v             v             v
       Tables       Listings       Figures
                        |
                        v
                 QC & VALIDATION
                        |
                        v
               FINAL STUDY OUTPUT

This is the basic journey from collected clinical data to statistical evidence.

22. What the Project Delivered

At the end of the programming cycle, the team delivered:

SDTM

  • DM

  • AE

  • CM

  • EX

  • LB

  • VS

  • DS

  • Other study-required domains

ADaM

  • ADSL

  • ADAE

  • ADLB

  • ADTTE

  • Additional analysis datasets required by the SAP

TLFs

  • Demographic tables

  • Disposition tables

  • Efficacy tables

  • Safety tables

  • Laboratory shift tables

  • AE listings

  • Kaplan-Meier figures

  • Other study-specific outputs

Quality Deliverables

  • Production programs

  • QC programs

  • Validation reports

  • Dataset specifications

  • Traceability documentation

  • Programming documentation


23. The Most Important Technical Lessons

The NC-201-301 project demonstrated several realities of Clinical SAS programming.

Lesson 1: SAS Is Only One Part of the Job

Knowing SAS syntax is important.

But it isn't sufficient.

A programmer must understand the clinical context.

Lesson 2: Specifications Drive Programming

The programmer should not make assumptions about:

  • Population definitions

  • Baseline

  • Treatment

  • Missing data

  • Censoring

  • Analysis windows

The SAP and approved specifications are the source of truth.

Lesson 3: SDTM and ADaM Require Different Thinking

SDTM focuses on standardized representation of collected clinical data.

ADaM focuses on analysis-ready datasets.

Understanding this distinction is fundamental.


Lesson 4: Data Quality Is a Programming Responsibility

A successful program is not simply one that executes.

The output must be:

Correct + Reproducible + Traceable + Validated

Lesson 5: Clinical Knowledge Adds Value

A programmer who understands the meaning of an adverse event, laboratory test or treatment exposure can ask better questions.

That is why professionals from pharmacy, biotechnology, life sciences, statistics and related disciplines can potentially build strong clinical programming profiles.


24. Where AI Fits Into This Workflow

Now imagine the same project in 2026.

The programming team has access to AI-assisted development tools.

AI can potentially help programmers:

  • Generate SAS code templates

  • Explain legacy programs

  • Suggest SQL logic

  • Identify potential coding errors

  • Draft documentation

  • Create test cases

  • Automate repetitive programming

  • Help analyze logs

  • Assist with data-quality investigations

But the core workflow remains:

Specification → Programming → Review → Validation → QC → Approval

AI doesn't remove the requirement for professional judgment.

If an AI tool generates a technically valid SAS program that implements the wrong clinical rule, the program is still wrong.

This is why the future Clinical SAS professional needs two capabilities:

Clinical programming expertise

and

AI literacy.


25. What Skills Would a Programmer Need to Work on This Project?

A programmer joining the NC-201-301 project would need a combination of technical and clinical skills.

SAS Programming

  • DATA step

  • PROC SQL

  • PROC SORT

  • PROC TRANSPOSE

  • Macro programming

  • Functions

  • Arrays

  • Formats

  • Debugging

Clinical Programming

  • Clinical trial terminology

  • Study design

  • Safety and efficacy concepts

  • Treatment exposure

  • Analysis populations

CDISC

  • SDTM

  • SDTMIG

  • ADaM

  • ADaMIG

  • Controlled Terminology

  • Define-XML concepts

Statistics

  • Descriptive statistics

  • Change from baseline

  • Frequency analysis

  • Time-to-event analysis

  • Kaplan-Meier concepts

Reporting

  • Tables

  • Listings

  • Figures

  • ODS

  • Output formatting

Quality

  • QC programming

  • PROC COMPARE

  • Log review

  • Traceability

  • Documentation

Modern Technology

  • Python fundamentals

  • Automation

  • Generative AI

  • AI-assisted programming


26. The Career Lesson Hidden Inside the Technical Project

There is an important career lesson behind this fictional project.

A company doesn't hire a Clinical SAS Programmer because the candidate knows how to write:

proc sort;
run;

It hires the person because that programmer can understand the larger problem:

How do we transform clinical trial data into reliable, standardized and analysis-ready information?

That is a much more valuable skill.

The syntax is simply the mechanism.

The real expertise lies in understanding the clinical data lifecycle.


Conclusion

At NovaCure Pharmaceuticals, the NC-201-301 project began with thousands of rows of raw clinical data.

It ended with standardized datasets, analysis-ready data and validated statistical outputs.

Between those two points was an enormous amount of reasoning.

The programmers had to understand:

Clinical research.

Data standards.

SAS programming.

Statistics.

Derivations.

Validation.

Quality control.

And increasingly:

Artificial intelligence.

That is what makes Clinical SAS programming a specialized profession.

It isn't simply about writing code.

It is about transforming clinical data into trustworthy evidence.

And as clinical trials become more data-intensive and technology continues to evolve, the professionals who understand both the science behind the data and the technology used to process it are likely to remain valuable.

The future Clinical SAS Programmer may not write every line of code manually.

They may use AI to generate, review and automate much of the routine work.

But they will still need to answer the most important question:

"Does this program correctly represent the clinical and statistical requirement?"

That is where technical skill becomes professional expertise.


Technical Case Study Summary

Project Component Implementation
Company NovaCure Pharmaceuticals Ltd.
Study NC-201-301
Phase III
Therapeutic Area Oncology
Subjects 612
Primary Endpoint Progression-Free Survival
Programming SAS 9.4
SDTM Domains DM, AE, CM, EX, LB, VS, DS, etc.
ADaM ADSL, ADAE, ADLB, ADTTE
Reporting Tables, Listings, Figures
QC Independent Programming + PROC COMPARE
Key Challenges Partial dates, duplicate records, treatment discrepancies, baseline derivation
Modern Enhancement AI-assisted programming and automation
Final Objective Validated, analysis-ready clinical trial data and statistical outputs

Important Disclaimer

NovaCure Pharmaceuticals Ltd., NC-201, NC-201-301, the clinical trial data, subject counts, study results, programming outputs and project events in this case study are entirely fictional and created for educational purposes. The technical workflow is designed to resemble a realistic Clinical SAS project, but it is not based on an actual pharmaceutical company's clinical trial or confidential industry data. Production implementations must follow the applicable study protocol, Statistical Analysis Plan, CDISC standards, programming specifications and organizational SOPs.