Start here →

Convert SAS programs to native PySpark

DATA step, PROC SQL, and macros parsed structurally. Emitted as set-based PySpark you can run on Databricks, EMR, or your own cluster.

Architecture

SAS in. PySpark out.

Deterministic parsers read the SAS estate and emit native PySpark code — not a Python while-loop that still reads one row.

SAS programs → SAS2PY parser → Native PySpark

SAS
Base SAS DATA step / macros
DI Studio Jobs + mappings
EG / EM Projects + flows
Viya / CAS CASL + actions
SAS2PY Parser
Deterministic parse AI optional
Row-level parity Before cutover
PySpark emit Set-based
Notebook / .py Your repo
PySpark
PySpark DataFrames
Python modules Reusable
Git Reviewed diffs
Any cluster Databricks / EMR / k8s

AI is an optional add-on, off by default — the conversion runs end to end without it, air-gapped if your estate requires it.

Why PySpark

The rewrite has to be set-based

Line-by-line Python is lift-and-shift

A for-loop over a SAS dataset is the same program in a new costume. We emit joins, windows, and aggregations.

You already picked Spark

Databricks, EMR, or on-prem Spark — the parser does not care. The notebook is portable.

Macros must disappear

Expanded before emit. The output is Python a Spark engineer can read.

Parser output

SAS DO loop to a set operation

A row-at-a-time running total — emitted as a filter and window, not a Python for-loop.

SAS
/* SAS row loop */
data gold;
  set txn;
  if amount > 1000;
  tot + amount;
run;
SAS2PY
converts
PySpark
# loop → filter + window
from pyspark.sql import functions as F
from pyspark.sql.window import Window
gold = txn.filter(F.col("amount") > 1000).withColumn(
    "tot", F.sum("amount").over(Window.orderBy("txn_date"))
)

The running total is a window. The filter is a predicate. No iterator.

Coverage

SAS to PySpark — artifact mapping

SASPySparkNotes
DATA stepDataFrame APINo row loops
PROC SQLspark.sqlSame joins
PROC MEANS / SUMMARYgroupBy + aggNative
MacroExpanded PythonReadable
SAS datasetParquet / Delta / IcebergYour choice
Validation

Every conversion validated to row-level parity

SAS output compared to PySpark output — row by row, column by column. Differences flagged before sign-off.

See how Data Matching works →
5,100
jobs
4.4M
LOC
$7.4M
saved
88%
no rewrite

National Grocer: 5,100 SAS jobs to open PySpark

Grid and DI Studio jobs rewritten as Apache PySpark on EMR and Glue. Same S3 prefixes. No lakehouse control plane required.

Read the case study →