--- title: '28 Ways to Be Missing in SAS' description: A SAS numeric missing is not a lone wolf - there are 28 of them, and Data Controller has handled all of them since v4. How they work, and what the validation rules do with them. date: '2026-09-22 09:00:00' author: 'Allan Bowe' authorLink: https://www.linkedin.com/in/allanbowe/ tags: - Special Missings - Data Quality previewImg: './cover.jpeg' --- # 28 Ways to Be Missing in SAS A numeric missing value in SAS is not a lone wolf. The ordinary missing (`.`) is one of **28** distinct missing values available for a numeric variable - the other 27 are written with a single character, the letters `A` to `Z` or an underscore (`._`). They exist because "missing" is usually not the whole story. A survey question that was never reached, a reading that was illegible, a value the respondent refused to give - in a well run process those are different facts, and a lone `.` throws the difference away. Special missings record *why* the value is missing. ## They are numbers, not text - Arithmetic on them yields missing - `.A + 1` is `.` - `proc means`, `proc summary` and friends exclude them, exactly as they exclude `.` - They sort below every non-missing number, in the order `._`, then `.`, then `.A` to `.Z` - The `NMISS()` and `CMISS()` functions count them as missing - Converting one to text drops the period - `cats(.A)` is the string `A` A display gotcha worth knowing: a regular missing prints as `.`, unless `options MISSING=` changes that character - set it to blank and a regular missing renders as an empty cell. The option affects only the regular missing; `._` and `.A`-`.Z` always print as their own letter. So a blank cell in a SAS listing is still unambiguously a regular missing, and a lone letter is still a special one. Data Controller itself is unaffected either way - it sends a regular missing to the browser as `null` and a special missing as its letter. In a SAS dataset they are written with a leading period (`.A`, `.B` ... `._`). In Data Controller you type just the letter or the underscore - no period - and the letter is not case sensitive. Two letters, or a letter mixed with a number, are refused rather than guessed. There is one cell where the letter cannot be typed at all. A numeric column that carries a date, datetime or time format is edited through a date picker rather than the numeric editor, and a picker accepts only a date. ## Carrying them between the browser and SAS The Data Controller frontend and the SAS backend exchange data as JSON, and JSON has no way to express a letter as a numeric value - `A` is a string. The conversion is handled in the open source [SASjs Adapter](https://github.com/sasjs/adapter#variable-types): - The adapter infers each column's SAS type from the values it is given. All numeric values means numeric; all strings means character; and a column holding a single character (`a`-`z`, `_` or `.`) alongside numeric values is numeric, with the lone characters written to SAS as special missings. - `null` becomes `.` or an empty string, according to the type derived for that column. - Two cases cannot be inferred from the values alone: a numeric column containing *only* special missings looks like a single character column, and a character column containing only nulls looks numeric. For those, the adapter accepts an explicit format for the column - and Data Controller sends one automatically, because it already knows each column's SAS format from the metadata returned by the backend. - A value that is neither a number nor a single valid character is refused rather than guessed (for example `aaaa`, or `!` in a numeric column), and a literal `.` is refused in favour of `null` for a regular missing. There is nothing to configure. Special missings are available by default, for numeric cells - a date, datetime or time formatted column aside, since those edit through a date picker. Once in SAS they are ordinary values, so they are what the approval DIFF screen compares, and the DIFF's formatted / unformatted switch shows either the formatted representation or the raw value - useful for confirming exactly which missing was set. ## What the Data Controller validation rules do with them These are Data Controller's own rules, configured per column in the `MPE_VALIDATIONS` table and applied in the browser as you edit and submit. - `NOTNULL` - works the same as SAS: cannot use special missings. A special missing is NULL to a NOT NULL (or primary key) constraint, so the rule rejects it, and so does a physical constraint on the target table - `HARDREGEX` - checked against the pattern like any other value; unlike blanks and the plain `.`, special missings are **not** exempt, so a numeric column that carries them needs a pattern which allows for a single letter - `SOFTREGEX` - the same check, but a failure is only a warning rather than a block, and it is ignored entirely if the column also has a `HARDREGEX` rule - `SOFTSELECT` / `HARDSELECT` - both support special missings; a soft dropdown never blocks a value, and a hard one lists them alongside the ordinary values - `ROUND` - harmless. It only rounds values that are numbers, so a special missing is left exactly as it was typed Special missings are **not supported** in a column that carries a range rule or a formula: - `MINVAL` / `MAXVAL` - a special missing sorts below every number, so `MINVAL` rejects it and `MAXVAL` accepts it while rejecting the column's real numbers. The rule's own value has to be a number too: put a special missing in `MINVAL` and every cell in the column fails, put one in `MAXVAL` and every real number fails - `HARDFORMULA` / `SOFTFORMULA` - a formula that reads a special-missing cell does not compute; the grid's spreadsheet engine returns `#VALUE!` for that row, where the plain `.` contributes 0 `CASE` (`UPCASE` / `LOWCASE`) is a character rule and does not come into it: SAS hands the browser a special missing as an uppercase letter, so there is no case to enforce, and a `CASE` rule on a numeric column would reject the column's numbers rather than the missing. One thing worth knowing about the regex rules: although the pattern is written in SAS PRX syntax, the check itself runs in the browser - SAS only parses the pattern (`PRXPARSE`) when the rule is saved - so the two engines can disagree on exotic patterns, and SAS pads a numeric-to-character conversion, so a pattern re-used in SAS needs `strip()` for an anchored match. In short, a special missing counts as a value for the pattern and dropdown rules, and as a missing value for everything that asks for a number. `video: [Managing Special Missing Values with Data Controller for SAS](https://www.youtube-nocookie.com/embed/ggrcNr23Jzw)` The recording shows the full cycle: typing special missings into numeric cells, the rejections, submitting the changes, approving them, and reviewing the DIFF - including a change from one special missing to another, and the formatted / unformatted switch on date and datetime columns.