sct ecl
Evaluate a SNOMED CT Expression Constraint Language (ECL) expression against the database and emit the matching concept SCTIDs.
When to use: you want the set of concepts a query selects - to pipe into another command, build a code list, feed a script, or paste into a SQL IN (…). ECL <<73211009 means "Diabetes mellitus and all its subtypes".
sct ecl is the reusable engine behind sct codelist add --ecl. Because it writes plain SCTIDs to stdout, it composes with everything else (see the composability principle).
Usage
sct ecl expand <EXPRESSION> [--db <FILE>] [-f text|json|yaml]
Options
| Argument / Flag | Default | Description |
|---|---|---|
<EXPRESSION> |
(required) | The ECL expression, e.g. "<<73211009". Pass - to read the expression from stdin. |
--db <FILE> |
discovered (see Path resolution) | SQLite database produced by sct sqlite. |
-f, --format <FMT> |
text |
Output format: text (newline-delimited ids), json (array), or yaml. (--json is a deprecated alias for --format json.) |
stdout is the result set (one SCTID per line, or a JSON array). The human-readable match count is written to stderr, so it never pollutes a pipe.
Examples
# Just the ids
sct ecl expand "<<73211009"
# Pipe into a code list (see `sct codelist add … -`)
sct ecl expand "<<73211009" | sct codelist add diabetes.codelist -
# Pipe into a lookup, or jq, or a file
sct ecl expand "<<73211009 MINUS <<46635009" > type2.txt
sct ecl expand "^447562003" -f json | jq length
# Read the expression itself from stdin
echo "<<404684003 : 363698007 = <<39057004" | sct ecl expand -
sct ecl compress - set → ECL
The inverse of expand: take an explicit set of SCTIDs (a hand-curated code list) and refactor it into a compact ECL expression that re-expands to exactly that set. Turns a brittle flat list into a self-documenting, release-stable intensional definition.
sct ecl compress [<IDS>...] [--codelist <FILE>] [--intensional-only]
[--max-exclusions <N>] [--pretty] [--stats] [--db <FILE>]
| Argument / Flag | Default | Description |
|---|---|---|
<IDS>... |
(stdin) | SCTIDs to compress. Pass - or no ids to read newline/whitespace-delimited ids from stdin. |
--codelist <FILE> |
- | Compress the effective members of a .codelist instead of ids. |
--intensional-only |
off | Emit only subsumption/exclusion clauses; do not add literal OR/MINUS residuals. Exits non-zero if the result is not exact. |
--max-exclusions <N> |
32 |
Cap the number of MINUS <<x clauses before the remainder falls to literal residuals. |
--pretty |
off | Break the expression across indented lines (text output only). |
--no-verify |
off | Skip the re-expansion check that verifies exactness (verification is on by default and cheap). |
--stats |
off | Print clause counts and intensional coverage to stderr. |
-f, --format <FMT> |
text |
text prints the ECL expression; json/yaml emit a structured object (expression plus include/exclude/residual breakdown). |
--db <FILE> |
discovered | SQLite database. |
--codelists <DIR> |
./codelists |
Registry directory for resolving bare includes: ids when compressing a --codelist (also $SCT_CODELISTS / [codelists] dir). |
By default the result is exact: if the subsumption heuristic can't express the set cleanly, literal OR id / MINUS id residuals are appended so the expression provably reproduces the input (verified by re-expansion). A set with no hierarchical structure degrades gracefully to a list of ORed ids - never to a wrong answer.
# A whole subtree collapses to one clause
sct ecl expand "<<73211009" | sct ecl compress - # => <<73211009
# Subtree-minus-subtree
sct ecl expand "<<73211009 MINUS <<46635009" | sct ecl compress - --stats # => <<73211009 MINUS <<46635009
# Round-trip: compress then expand returns the original set
sct ecl compress --codelist diabetes.codelist | sct ecl expand -
This is a greedy heuristic, not a proof of minimum size; --stats reports how much was expressed intensionally. See spec/commands/ecl-compress.md.
Supported ECL
| Construct | Example | Meaning |
|---|---|---|
| Self | 73211009 |
the concept itself |
| Wildcard | * |
any concept |
| Descendants | <73211009 / <<73211009 |
descendants / descendants-or-self |
| Ancestors | >73211009 / >>73211009 |
ancestors / ancestors-or-self |
| Children / parents | <!73211009 / >!73211009 |
direct children / parents |
| Refset member | ^447562003 |
members of the reference set |
| Boolean | A AND B, A OR B, A MINUS B |
intersection / union / difference |
| Refinement | <<404684003 : 363698007 = <<39057004 |
attribute constraint (comma-conjoined, { } groups, !=) |
Optional |term| annotations are accepted and ignored. Attribute refinement (the : operator) needs a database built with schema v4+ (which adds the concept_relationships table); hierarchy and refset queries work on any database. Not yet supported (clear error, never silent mis-evaluation): cardinality [min..max], reverse R and dotted . attributes. See spec/ecl.md.