diff --git a/content/feed/sas-special-missings/index.md b/content/feed/sas-special-missings/index.md index 0ddcca3..3fc03d2 100644 --- a/content/feed/sas-special-missings/index.md +++ b/content/feed/sas-special-missings/index.md @@ -24,6 +24,8 @@ They exist because "missing" is usually not the whole story. A survey question t - 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. ## Carrying them between the browser and SAS @@ -39,15 +41,17 @@ There is nothing to configure. Special missings are available by default, for nu 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 validation rules do with them +## What the Data Controller validation rules do with them -A special missing is a value somebody deliberately set, so the rules treat it as a value - it is not blank, and it is not exempt: +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. A special missing is a value somebody deliberately set, so the rules treat it as a value - it is not blank, and it is not exempt: - `NOTNULL` - passes, because it is not null - `MINVAL` - fails, because a special missing sorts below every number and so is below any minimum - `MAXVAL` - passes, for the same reason it is below any maximum -- `CASE` (`UPCASE` / `LOWCASE`) - compared as text, so `A` passes `UPCASE` but `a` does not -- `HARDREGEX` / `SOFTREGEX` - 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 +- `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 + +`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. That is usually what you want - a value recorded as "not collected" should not quietly satisfy a completeness or range rule. It does mean a range rule on a column that uses special missings will warn on those rows, which is the signal to either accommodate them in the rule or not use special missings on that column. @@ -70,6 +74,7 @@ They are real numeric values, not text: - PROC MEANS excludes them, like any other missing - they sort below every number: ._ then . then .A to .Z - NMISS() and CMISS() count them as missing +- a regular missing prints as . unless options MISSING changes it - and that option never touches a special missing The hard part is every tool that is not SAS. JSON has no way to say "this number is a letter" - A is just a string. So a value that is perfectly legal in a SAS dataset quietly breaks in the browser, in Excel, in an API. @@ -79,11 +84,13 @@ We solved that in the open source SASjs Adapter, and it has been in Data Control - where the type cannot be inferred - a numeric column holding ONLY special missings - Data Controller passes the column format explicitly - you type the letter on its own: a or A, no period, and case does not matter -And they behave like values in DC's validation rules, which is usually what you want: +And they behave like values in Data Controller's validation rules, which is usually what you want: - NOTNULL passes - it is not null - MINVAL fails - it sorts below every number; MAXVAL passes for the same reason - HARDREGEX checks it against the pattern, unlike blanks and plain . +- SOFTREGEX warns instead of blocking (and is ignored if the column also has a HARDREGEX) +- CASE is a character rule, so it has no place on a numeric column So a value recorded as "not collected" cannot quietly satisfy a completeness or range rule.