Syntax Reference#
A reference for the Data Step statements supported by limulus.
For differences from SAS language, see Differences from SAS language.
For column-oriented API and session-level helpers such as sort, sql, and include, see API Reference and Changelog.
DATA Statement#
data <output1> [<output2> ...];
...
run;
Specifying multiple output destinations creates a multi-output DATA step.
Using an explicit output statement allows row-level routing.
SET Statement#
set <dataset> [<dataset2> ...] [end=<var>] [indsname=<var>];
Option |
Description |
|---|---|
|
Defines a variable that becomes |
|
Stores the current dataset name in a variable |
Listing multiple datasets performs a vertical concatenation.
Shared columns must have matching types; mixed Arrow string and large_string
columns are promoted to large_string.
Interleaving with BY#
set <dataset1> <dataset2> ...;
by <key>;
When by is specified together with multiple datasets, rows from all sources are
merge-sorted by the BY key rather than concatenated in source order.
This matches “interleaving” semantics.
data combined;
set sales2023 sales2024;
by date;
run;
MERGE Statement#
merge <dataset>(in=<var>) [<dataset2>(in=<var>)];
by <key>;
Duplicate non-BY column names raise an error instead of being overwritten.
Repeated BY values across multiple inputs produce a warning.
BY keys must have matching types; mixed Arrow string and large_string keys
are promoted to large_string.
WHERE Statement#
where <condition>;
Placed after SET/MERGE. Applies a filter at data read time.
Subsetting IF Statement#
if <condition>;
Applies a filter after data is read.
IF / ELSE IF / ELSE Statement#
if <condition> then <statement>;
else if <condition> then <statement>;
else <statement>;
Use DO...END to group multiple statements:
if x > 0 then do;
y = x * 2;
z = 1;
end;
DO / END Statement#
do <var> = <start> to <stop> [by <step>];
...
end;
Used for counter loops as well as conditional blocks (if...then do;).
BY Statement#
by <var> [<var2> ...];
Used in combination with SET/MERGE.
Makes FIRST.<var> / LAST.<var> automatic variables available.
OUTPUT Statement#
output [<dataset>];
Without arguments, writes to the default destination: the first named OUTPUT
target, or the first DATA target if no named OUTPUT exists.
With names, writes to the specified destinations.
Output references accept dataset options such as KEEP, DROP, and RENAME.
References to the same destination share its options.
STOP Statement#
stop ;
Stops the Data Step processing.
KEEP / DROP Statement#
keep <var1> [<var2> ...];
drop <var1> [<var2> ...];
Specifies variables to include in / exclude from the output dataset.
RENAME Statement#
rename <oldname>=<newname> [<oldname>=<newname> ...];
RETAIN Statement#
retain <var> [<initial>] [<var2> [<initial2>] ...];
Retains the value of a variable across iterations. If the initial value is omitted, defaults to null.
ARRAY Statement#
array <name> <var1> [<var2> ...];
Assigns a name to a group of variables. Index access (name[1]) is supported.
SUM Statement (Cumulative Addition)#
<var> + <expression>;
Performs cumulative addition without RETAIN.
ASSIGN Statement (Assignment)#
<varname> = <expression>;
String Concatenation in General Expressions#
Two strings can be joined with + or ||, preserving spaces:
text_value = "a" + "B"; /* "aB" */
digits = "1" + "2"; /* "12" */
joined = "a" || "B"; /* "aB" */
These forms apply to Data Step expressions, not the Column API or dataset-option
WHERE=.
DELETE Statement#
delete;
Does not output the current row (moves to the next iteration of the PDV loop).
Built-in Functions#
String#
String positions and lengths use Unicode characters rather than bytes.
Function |
Description |
Example |
|---|---|---|
|
Substring |
|
|
Convert to uppercase |
|
|
Convert to lowercase |
|
|
Capitalize first letter |
|
|
Remove trailing spaces |
|
|
Remove leading and trailing spaces |
|
|
String length |
|
|
NULL-safe string length |
|
|
Reverse string |
|
|
n-th token |
|
|
Remove specified characters |
|
|
Position of substring |
|
|
Position of substring |
|
|
Word replacement |
|
|
Character translation |
|
|
Word count |
|
|
Concatenate |
|
|
Concatenate with trim |
|
|
Concatenate with trailing trim |
|
|
Concatenate with delimiter |
|
|
Repeat n times |
|
Numeric#
Function |
Description |
Example |
|---|---|---|
|
Absolute value |
|
|
Round (0.5 rounds away from zero) |
|
|
Ceiling |
|
|
Floor |
|
|
Integer part |
|
|
Remainder |
|
|
Maximum |
|
|
Minimum |
|
|
Sum |
|
|
Mean |
|
|
Square root |
|
|
Natural logarithm |
|
|
Exponent |
|
|
Sign |
|
Missing Values / Dates#
Function |
Description |
Example |
|---|---|---|
|
Returns |
|
|
Count of missing values |
|
|
Count of missing values (mixed types) |
|
|
Previous row’s value |
|
|
Month/day/year to date |
|
|
Year from date |
|
|
Date difference |
|
Format Helpers#
Function |
Description |
Example |
|---|---|---|
|
Render a value as text with a built-in or registered format |
|
|
Parse text into a numeric, date, datetime, or time value |
|
|
Convert a time-like value to decimal hours |
|
Built-in put(...) formats currently support:
numeric to text:
best.,w.,w.d,w.d.,zw.,zw.d,zw.d.,commaw.,commaw.d,commaw.d.date / datetime / time to text:
e8601da.,e8601dt.,yymmdd6.,yymmdd8.,yymmdd10.,time.
Built-in input(...) informats currently support:
text to numeric:
best.text to date / datetime / time:
e8601da.,e8601dt.,yymmdd6.,yymmdd8.,yymmdd10.,time.
Session-level custom catalogs can also be registered for exact-match lookups:
Session.register_format(name, mapping)registers a numericput(...)catalog.Session.register_format(name, mapping, namespace="character")registers a characterput(...)catalog referenced as$name..Session.register_informat(name, mapping)registers a float64-onlyinput(...)catalog.
Current dict-catalog semantics are intentionally narrow:
put(value, myfmt.)returns text and falls back to the original value when no dict entry matches.put(value, $myfmt.)uses the same base name with the character-format namespace.input(value, myinf.)returnsnullwhen no dict entry matches.dict custom
input(...)is float64-only in this phase; typed custom informats remain deferred.callable format/informat registrations are unsupported; custom catalogs must be serializable mappings.
Regular Expressions#
Function |
Description |
Example |
|---|---|---|
|
Regex match position |
|
|
Regex substitution |
|
ARRAY Helpers#
Function |
Description |
Example |
|---|---|---|
|
Number of elements in array |
|
|
Variable name of array element |
|
Custom Functions#
Function |
Description |
Example |
|---|---|---|
|
Next row’s value |
|
|
negative n behaves like |
|
|
Apply a Python callable by name. |
|
Note:
apply()supports builtins, dotted functions such asmath.sqrt, and your own functions registered withfunctions={"name": callable}.