Working with NCBI¶
MIINT provides integration with NCBI's GenBank and RefSeq.
Table of contents¶
- Accessions are literals, not table names - Applies to all three readers below; includes the idiom for driving them from accessions held in a table.
- Read metadata - Fetch record metadata from GenBank and RefSeq by accession.
- Read sequences - Fetch sequence data from GenBank and RefSeq by accession.
- Read annotations - Fetch annotation data from GenBank and RefSeq by accession.
- Taxonomy - Obtain and use the NCBI taxonomy: the full tree (bulk/offline), online lineage lookups, and offline lineage collapse.
- Read the taxonomy tree (
read_ncbi_taxdump) - Bulk/offline: download + cache the taxonomy tree. - Remap retired taxids (
read_ncbi_taxdump_merged) - The retired→current taxid map. - Read every name class (
read_ncbi_taxdump_names) - All ofnames.dmp, includinggenbank common name. - List deleted taxids (
read_ncbi_taxdump_deleted) - The taxids NCBI deleted outright. - Look up lineages online (
read_ncbi_lineage) - Online/rate-limited: resolve a handful of taxids via E-utilities. - Collapse the tree to lineages (
taxonomy_lineage) - Offline: rank-collapse a taxdump tree, identical schema toread_ncbi_lineage.
Accessions are literals, not table names¶
read_ncbi, read_ncbi_fasta and read_ncbi_annotation take literal accessions — a VARCHAR or a
VARCHAR[]. Passing the name of a table that holds accessions is rejected at bind time:
CREATE TABLE my_accessions AS SELECT 'NC_001416.1' AS accession;
SELECT * FROM read_ncbi_annotation('my_accessions');
-- Invalid Input Error: read_ncbi_annotation: 'my_accessions' is a table in the catalog,
-- not an NCBI accession. ...
To drive one of these functions from accessions held in a table, hoist them into a list first. A
subquery cannot be used as a table-function argument at all (Binder Error: Table function cannot
contain subqueries), so use SET VARIABLE + getvariable():
SET VARIABLE accs = (SELECT list(accession) FROM my_accessions);
SELECT * FROM read_ncbi_annotation(getvariable('accs'));
The check keys off whether the string resolves to a table or view in the catalog, not off the string's
shape — accession formats are open-ended (bare GenBank ids such as J02459 carry no distinguishing
prefix), so a pattern test would reject valid input. A name that is not in the catalog is still sent
upstream as an accession.
Both bare and qualified names are covered: a bare name is resolved against the session search_path,
and a qualified one (my_schema.accs, my_db.my_schema.accs) is resolved as written. Versioned
accessions are unaffected — 'NC_001416.1' is looked up as schema NC_001416 / relation 1, finds
nothing, and is sent upstream unchanged.
Read metadata¶
Fetch GenBank and RefSeq metadata from NCBI by accession number. This function queries NCBI's E-utilities API to retrieve sequence metadata without downloading the full sequence.
Requirements:
- Requires the httpfs extension (automatically loaded)
- Network access to NCBI servers (eutils.ncbi.nlm.nih.gov)
Parameters:
- accession (VARCHAR or VARCHAR[]): NCBI accession number(s) (e.g., 'NC_001416.1', 'NM_001101.5')
- api_key (VARCHAR, optional): NCBI API key for higher rate limits (10 req/s vs 3 req/s)
- batch_size (BIGINT, optional, default 500): Number of accessions per epost+efetch round-trip. Larger batches reduce per-accession HTTP overhead; the default matches NCBI's practical guidance for POST.
Output schema:
- accession (VARCHAR): Accession with version (e.g., 'NC_001416.1')
- version (INTEGER): Version number extracted from accession
- description (VARCHAR): Sequence description/definition
- organism (VARCHAR): Source organism name
- taxonomy_id (BIGINT): NCBI taxonomy ID
- length (BIGINT): Sequence length in base pairs
- molecule_type (VARCHAR): Molecule type (e.g., 'DNA', 'RNA', 'protein')
- update_date (DATE): Last modification date
Behavior:
- Fetches GenBank XML format from E-utilities using the batched epost + efetch handshake (one POST + one GET per batch_size accessions)
- Automatically detects accession type (RefSeq NC_/NM_/NP_, GenBank, etc.)
- Rate-limited to respect NCBI guidelines (3 req/s without key, 10 req/s with key)
- Retry logic for transient failures (400, 408, 429, 500, 502, 503, 504) with exponential backoff up to 6 retries
- Accessions silently omitted by NCBI (e.g. invalid IDs) are reported via miint_warnings() and a stderr WARNING; the function does not throw, so one bad accession in a batch never aborts the rest of the query
Examples:
-- Get metadata for a single accession
SELECT * FROM read_ncbi('NC_001416.1');
-- Get metadata for multiple accessions
SELECT * FROM read_ncbi(['NC_001416.1', 'NC_001422.1']);
-- Use API key for higher rate limits
SELECT * FROM read_ncbi('NC_001416.1', api_key='your_ncbi_api_key');
-- Get organism and length for a set of sequences
SELECT accession, organism, length
FROM read_ncbi(['NC_001416.1', 'NC_001422.1', 'NC_000913.3']);
-- Filter by molecule type
SELECT accession, description
FROM read_ncbi(['NC_001416.1', 'NM_001101.5'])
WHERE molecule_type = 'DNA';
Notes:
- Empty accessions raise InvalidInputException at bind time
- A table or view name passed where an accession belongs is rejected at bind time — see Accessions are literals, not table names
- Invalid accessions that NCBI silently drops appear in miint_warnings() (filter with SELECT * FROM miint_warnings() WHERE message LIKE '%read_ncbi%') — they do not raise
- For bulk downloads, set api_key for the higher 10 req/s rate; with the default batch_size=500 a 10,000-accession query is bound by ~20 round-trips, not by the per-accession rate cap
Read sequences¶
Fetch FASTA sequences from NCBI by accession number. Returns data in the same schema as read_fastx, making it easy to combine NCBI sequences with local files.
Requirements:
- Requires the httpfs extension (automatically loaded)
- Network access to NCBI servers (eutils.ncbi.nlm.nih.gov)
Parameters:
- accession (VARCHAR or VARCHAR[]): NCBI accession number(s) (e.g., 'NC_001416.1')
- api_key (VARCHAR, optional): NCBI API key for higher rate limits
- include_filepath (BOOLEAN, optional, default false): Add filepath column showing NCBI URL
- batch_size (BIGINT, optional, default 500): Number of sequence accessions per epost+efetch round-trip. Assembly accessions (GCF_/GCA_) are always fetched one at a time via the Datasets API, so this parameter only affects the sequence (NC_/NM_/...) path.
Output schema (matches read_fastx):
- sequence_index (BIGINT): 0-based sequential index
- read_id (VARCHAR): Accession number extracted from FASTA header
- comment (VARCHAR, nullable): Description from FASTA header
- sequence1 (VARCHAR): DNA/RNA sequence
- sequence2 (VARCHAR): Always NULL (single sequences only)
- qual1 (UINT8[]): Always NULL (FASTA has no quality scores)
- qual2 (UINT8[]): Always NULL
- filepath (VARCHAR, optional): NCBI E-utilities URL when include_filepath=true
Behavior:
- Fetches FASTA via the batched epost + efetch handshake (sequence accessions); assemblies route through the Datasets API one at a time
- Parses pipe-delimited FASTA headers (e.g., gi|123|ref|NC_001416.1|description)
- Extracts accession as read_id, remainder as comment
- Rate-limited and retried on transient failures (400, 408, 429, 5xx) with exponential backoff up to 6 retries
- Accessions silently omitted by NCBI are reported via miint_warnings() and stderr WARNING; the function does not throw on missing accessions, so one bad ID in a 10,000-accession query never aborts the rest
Examples:
-- Fetch a single sequence
SELECT * FROM read_ncbi_fasta('NC_001416.1');
-- Fetch multiple sequences
SELECT read_id, LENGTH(sequence1) AS seq_length
FROM read_ncbi_fasta(['NC_001416.1', 'NC_001422.1']);
-- Combine NCBI sequences with local files
SELECT read_id, sequence1 FROM read_ncbi_fasta('NC_001416.1')
UNION ALL
SELECT read_id, sequence1 FROM read_fastx('local_sequences.fasta');
-- Export NCBI sequence to local FASTA file
COPY (SELECT * FROM read_ncbi_fasta('NC_001416.1'))
TO 'lambda_phage.fasta' (FORMAT FASTA);
-- Get sequence with source URL tracking
SELECT read_id, LENGTH(sequence1) AS length, filepath
FROM read_ncbi_fasta('NC_001416.1', include_filepath=true);
-- Use as reference for alignment
CREATE TABLE reference AS SELECT * FROM read_ncbi_fasta('NC_001416.1');
CREATE TABLE reads AS SELECT * FROM read_fastx('reads.fastq');
SELECT * FROM align_minimap2('reads', 'reference');
Notes:
- Large sequences (e.g., complete chromosomes) may take time to download
- Output is compatible with all functions expecting read_fastx schema
- Empty accessions raise InvalidInputException at bind time
- A table or view name passed where an accession belongs is rejected at bind time — see Accessions are literals, not table names
- Missing/invalid accessions appear in miint_warnings() rather than raising — query that table to see what NCBI dropped after a large batched fetch
Read annotations¶
Fetch feature annotations from NCBI by accession number. Returns data in the same schema as read_gff, making it easy to analyze NCBI annotations with SQL.
Requirements:
- Requires the httpfs extension (automatically loaded)
- Network access to NCBI servers (eutils.ncbi.nlm.nih.gov)
Parameters:
- accession (VARCHAR or VARCHAR[]): NCBI accession number(s) (e.g., 'NC_001416.1')
- api_key (VARCHAR, optional): NCBI API key for higher rate limits
- include_filepath (BOOLEAN, optional, default false): Add filepath column showing NCBI URL
Output schema (matches read_gff):
- seqid (VARCHAR): Sequence/chromosome identifier (the accession)
- source (VARCHAR): Annotation source ('RefSeq', 'GenBank', or 'NCBI')
- type (VARCHAR): Feature type (e.g., 'gene', 'CDS', 'mRNA')
- position (INTEGER): 1-based start position
- stop_position (INTEGER): 1-based half-open end position — i.e. NCBI's annotation end + 1, normalized on read so it matches every other miint function. A feature's length is stop_position - position, with no + 1. The raw NCBI end is stop_position - 1. This changed: it previously emitted the closed end directly. See Coordinate conventions.
- score (DOUBLE, nullable): Feature score (typically NULL for NCBI data)
- strand (VARCHAR): Strand ('+' or '-')
- phase (INTEGER, nullable): CDS phase (0, 1, 2) derived from codon_start qualifier
- attributes (MAP(VARCHAR, VARCHAR)): Key-value attributes (gene, product, locus_tag, etc.)
- filepath (VARCHAR, optional): NCBI E-utilities URL when include_filepath=true
Behavior: - Fetches INSDC feature table format from E-utilities - Converts to GFF3-compatible schema - Detects source automatically from accession prefix (RefSeq for NC_/NM_, etc.) - Handles complement strand (reversed positions) - Parses codon_start qualifier to set correct CDS phase - Warns on complex locations (join, complement) - uses outer bounds - A table or view name passed where an accession belongs is rejected at bind time — see Accessions are literals, not table names
Examples:
-- Get all annotations for Lambda phage
SELECT * FROM read_ncbi_annotation('NC_001416.1');
-- Get only genes
SELECT seqid, position, stop_position, attributes['gene'] AS gene_name
FROM read_ncbi_annotation('NC_001416.1')
WHERE type = 'gene';
-- Get CDS features with their products
SELECT position, stop_position, strand, phase,
attributes['gene'] AS gene,
attributes['product'] AS product
FROM read_ncbi_annotation('NC_001416.1')
WHERE type = 'CDS';
-- Count feature types
SELECT type, COUNT(*) AS count
FROM read_ncbi_annotation('NC_001416.1')
GROUP BY type
ORDER BY count DESC;
-- Combine annotations from multiple genomes
SELECT seqid, type, COUNT(*) AS feature_count
FROM read_ncbi_annotation(['NC_001416.1', 'NC_001422.1'])
GROUP BY seqid, type
ORDER BY seqid, feature_count DESC;
-- Find genes on the minus strand
SELECT attributes['gene'] AS gene_name, position, stop_position
FROM read_ncbi_annotation('NC_001416.1')
WHERE type = 'gene' AND strand = '-';
-- Export to local GFF-like format
COPY (
SELECT seqid, source, type, position, stop_position,
NULL AS score, strand, phase
FROM read_ncbi_annotation('NC_001416.1')
) TO 'lambda_features.tsv' (DELIMITER '\t', HEADER);
Notes:
- Output is compatible with queries designed for read_gff
- Complex feature locations (join, complement) emit a warning and use outer bounds only
- The phase column is set from the codon_start qualifier for CDS features
- Source is detected from accession prefix: NC_/NM_/NP_ -> 'RefSeq', others -> 'GenBank' or 'NCBI'
Taxonomy¶
read_ncbi(...) returns a taxonomy_id per accession, but a bare taxid is not very
useful on its own. These functions turn taxids into ranks, scientific names, and full
lineages, and let you navigate the NCBI taxonomy as a tree.
There are two acquisition paths, chosen by how much of the taxonomy you need:
| Function | Use when | |
|---|---|---|
| Bulk / offline | read_ncbi_taxdump (+ taxonomy_lineage) |
You need the whole taxonomy, join against many taxids, or want to work without repeated network calls. Downloads the full dump once (~450 MB extracted) and caches it. |
| Online / rate-limited | read_ncbi_lineage |
You have a handful of taxids and just want their lineages. One E-utilities round-trip per batch; subject to NCBI rate limits. |
taxonomy_lineage (offline) and read_ncbi_lineage (online) emit the identical
schema, so you can develop against the API and switch to the cached dump at scale
without changing downstream SQL.
The NCBI taxonomy is a tree in the exact shape read_newick emits, so read_ncbi_taxdump
output (node_index, parent_index, name, is_tip, plus rank) drops straight into
the existing tree tooling.
Malformed input fails loudly. All four taxdump readers validate what they parse rather than coercing it, because a taxonomy that silently reads slightly wrong is worse than one that refuses to read:
- Field widths are checked exactly for
names.dmp(4),merged.dmp(2) anddelnodes.dmp(1) — the widths NCBI'staxdump_readme.txtdocuments and whose every field is consumed. A row of a different width means the layout moved, and reading it positionally would return aname_classthat is really aunique_name: well-formed to every downstream check. Errors name the member and line.nodes.dmpis checked as a lower bound instead, since its documented width differs betweentaxdump(13 fields) andnew_taxdump(18) and only the first three are read. - Taxids must be integers outright. A non-numeric, partially-numeric (
123abc) or out-of-range value is rejected rather than becoming0, being truncated, or clamping toINT64_MAX— the latter two land inside the valid taxid range where no caller could tell them from real data. - A reader requires the member it reads, and only that member (see
read_ncbi_taxdump_deleted).
Read the taxonomy tree (read_ncbi_taxdump)¶
Reads NCBI's taxonomy dump into the tree-table schema. With no argument it downloads the canonical dump from NCBI and caches the extracted files locally, so subsequent calls are fast and offline.
Requirements:
- Requires the httpfs extension (automatically loaded) only when downloading or reading a remote source
- Network access to NCBI (ftp.ncbi.nlm.nih.gov) for the default download
Parameters:
- source (VARCHAR, positional, optional): where to read the dump from. Omit (or pass NULL) to auto-download the default dump. May be:
- a directory of already-extracted .dmp files (read directly; no download/untar)
- a local or remote (http:///https://) taxdump.tar.gz archive (streamed, gunzipped, and untarred)
- refresh (BOOLEAN, optional, default false): re-download the default dump even if a cached copy exists
Output schema (tree-table + rank, consistent with read_newick):
- node_index (BIGINT): the tax_id
- parent_index (BIGINT, nullable): the parent tax_id; NULL for the root (NCBI self-parents taxid 1)
- name (VARCHAR): scientific name (name_class = 'scientific name'). Every other name class — synonyms, genbank common name, authorities — is reached via read_ncbi_taxdump_names, not here
- rank (VARCHAR): raw NCBI rank string (e.g. superkingdom, domain, phylum, ..., strain, no rank)
- is_tip (BOOLEAN): true iff no node lists this node as its parent
Behavior:
- Default source is https://ftp.ncbi.nlm.nih.gov/pub/taxonomy/taxdump.tar.gz
- The extracted .dmp files are cached under ${XDG_CACHE_HOME:-$HOME/.cache}/miint/taxonomy/, so download + gunzip + untar happen once; later reads hit the fast local-directory path. Set MIINT_TAXONOMY_CACHE_DIR to override the cache location.
- The tree contains live nodes only. Merged-away taxids live in read_ncbi_taxdump_merged, deleted ones in read_ncbi_taxdump_deleted; neither appears here.
- Emitted faithfully — unclassified/environmental/no rank nodes are included, not filtered.
Examples:
-- Download (once) and read the whole NCBI taxonomy
SELECT COUNT(*) FROM read_ncbi_taxdump();
-- Read a previously extracted dump directory (fully offline)
SELECT node_index, parent_index, name, rank
FROM read_ncbi_taxdump('/data/taxonomy/')
WHERE node_index = 562;
-- Read a specific archive (local or remote)
SELECT * FROM read_ncbi_taxdump('/downloads/taxdump.tar.gz');
-- Force a fresh download of the default dump
SELECT COUNT(*) FROM read_ncbi_taxdump(refresh := true);
-- Join sequence metadata's taxonomy_id against the tree
SELECT m.accession, t.name AS organism, t.rank
FROM read_ncbi(['NC_001416.1', 'NC_000913.3']) m
JOIN read_ncbi_taxdump() t ON t.node_index = m.taxonomy_id;
Remap retired taxids (read_ncbi_taxdump_merged)¶
NCBI periodically merges taxids; the merged (retired) ids never appear in the live tree.
This exposes the retired→current map from merged.dmp so you can remap taxids in your own
data before joining against the tree — a naive join would silently drop merged taxids.
Parameters: same source / refresh as read_ncbi_taxdump.
Output schema:
- old_taxid (BIGINT): the retired taxid
- new_taxid (BIGINT): the current taxid it was merged into
Example:
-- Remap possibly-retired taxids to current ones, then join the tree
WITH remap AS (SELECT * FROM read_ncbi_taxdump_merged())
SELECT d.my_taxid, COALESCE(r.new_taxid, d.my_taxid) AS current_taxid, t.name
FROM my_data d
LEFT JOIN remap r ON r.old_taxid = d.my_taxid
LEFT JOIN read_ncbi_taxdump() t ON t.node_index = COALESCE(r.new_taxid, d.my_taxid);
Read every name class (read_ncbi_taxdump_names)¶
read_ncbi_taxdump collapses each taxon to its scientific name, which leaves the rest of
names.dmp unreachable. This is the verbatim view of that member: one row per name,
no class filtered out. Use it when you need a second name for a taxon — most often
genbank common name, which is what someone searching for a taxon is likely to type.
Parameters: same source / refresh as read_ncbi_taxdump.
Output schema:
- taxid (BIGINT): the taxon the name belongs to
- name (VARCHAR): the name itself (name_txt)
- unique_name (VARCHAR): NCBI's disambiguator, supplied when a name string is shared across taxa; empty string (not NULL) on most rows
- name_class (VARCHAR): which kind of name this is
Behavior:
- Rows are emitted in file order, so a taxon's names are grouped but not sorted by class
- A taxon has exactly one scientific name but may carry several rows of another class, so aggregate rather than assuming one row per (taxid, class) pair
- Reads only names.dmp — not the whole dump — so it can be joined against the other readers without each one paying for members it does not use
- The classes present in the current dump, by frequency: scientific name, authority, type material, synonym, includes, equivalent name, genbank common name, common name, acronym, in-part, blast name. Only ~1% of taxa have a genbank common name, so expect NULL for most.
Examples:
-- Scientific name alongside the genbank common name, one row per taxon
SELECT taxid,
MAX(name) FILTER (name_class = 'scientific name') AS scientific_name,
MAX(name) FILTER (name_class = 'genbank common name') AS common_name
FROM read_ncbi_taxdump_names()
WHERE taxid IN (9606, 10090, 562)
GROUP BY taxid;
-- 9606 | Homo sapiens | human
-- 10090 | Mus musculus | house mouse
-- 562 | Escherichia coli | NULL <- no genbank common name
-- Every name NCBI records for one taxon
SELECT name_class, name FROM read_ncbi_taxdump_names() WHERE taxid = 9606;
-- Resolve a free-text name to a taxid across all classes
SELECT DISTINCT taxid FROM read_ncbi_taxdump_names() WHERE name ILIKE 'house mouse';
List deleted taxids (read_ncbi_taxdump_deleted)¶
NCBI deletes taxids outright as well as merging them. A deleted taxid appears in neither
the live tree nor read_ncbi_taxdump_merged, so without this member it is
indistinguishable from a taxid that never existed — and a stored taxid that stops
resolving cannot be told apart from bad input. This exposes delnodes.dmp.
Parameters: same source / refresh as read_ncbi_taxdump.
Output schema:
- taxid (BIGINT): the deleted taxid
There is no replacement column: unlike a merge, a deletion names no successor.
Behavior:
- A dump carrying no delnodes.dmp is an error, not zero rows. "Nothing was deleted" and "the extraction was incomplete" must not look alike to a caller that treats the result as authoritative — an empty answer read as truth would un-retire every taxid NCBI has deleted. Each reader requires only the member it reads, so a dump without delnodes.dmp is still perfectly usable via read_ncbi_taxdump and read_ncbi_taxdump_names.
- Deletions substantially outnumber merges (~778k vs ~100k in the current dump)
- The live, merged, and deleted id sets are mutually disjoint — a taxon is exactly one of the three
Examples:
-- Classify stored taxids as live, merged away, or deleted
SELECT d.my_taxid,
CASE WHEN t.node_index IS NOT NULL THEN 'live'
WHEN m.old_taxid IS NOT NULL THEN 'merged'
WHEN x.taxid IS NOT NULL THEN 'deleted'
ELSE 'unknown' END AS status,
m.new_taxid AS replaced_by
FROM my_data d
LEFT JOIN read_ncbi_taxdump() t ON t.node_index = d.my_taxid
LEFT JOIN read_ncbi_taxdump_merged() m ON m.old_taxid = d.my_taxid
LEFT JOIN read_ncbi_taxdump_deleted() x ON x.taxid = d.my_taxid;
-- How many taxids has NCBI deleted?
SELECT COUNT(*) FROM read_ncbi_taxdump_deleted();
Look up lineages online (read_ncbi_lineage)¶
Resolves a small set of taxids to full lineages via NCBI E-utilities (efetch,
db=taxonomy). This is the online path — for large taxid sets or repeated use, prefer
the cached read_ncbi_taxdump + taxonomy_lineage, which emit the identical schema.
Requirements:
- Requires the httpfs extension (automatically loaded)
- Network access to NCBI (eutils.ncbi.nlm.nih.gov)
Parameters:
- taxid (BIGINT or BIGINT[]): the taxon(s) to resolve
- api_key (VARCHAR, optional): NCBI API key for higher rate limits (10 req/s vs 3 req/s)
- batch_size (BIGINT, optional, default 500, max 10000): taxids per epost+efetch round-trip
Output schema (the shared lineage schema, identical to taxonomy_lineage):
- taxid (BIGINT): the query taxon
- name (VARCHAR): its scientific name
- rank (VARCHAR): its rank
- domain, phylum, class, "order", family, genus, species, strain (VARCHAR): the rank-collapsed lineage; NULL where that rank is absent. class and order are SQL reserved words — quote "order" (and, when needed, "class") in queries.
- lineage (VARCHAR): formatted d__…;p__…;c__…;o__…;f__…;g__…;s__…, with ;t__<strain> appended when a strain is present
Behavior:
- Both the legacy superkingdom and the newer domain rank collapse to the domain column (NCBI is mid-transition)
- Taxids silently omitted by NCBI are reported via miint_warnings(), not raised; a taxid that NCBI has since merged is recognised as resolved (via the response's AkaTaxIds) rather than reported as missing
- Rate-limited and retried on transient failures with exponential backoff
Examples:
-- One taxid
SELECT * FROM read_ncbi_lineage(562);
-- Several taxids
SELECT taxid, name, genus, species, lineage
FROM read_ncbi_lineage([562, 9606]);
-- Higher rate limit with an API key
SELECT taxid, lineage FROM read_ncbi_lineage([562, 9606], api_key := 'your_ncbi_api_key');
Collapse the tree to lineages (taxonomy_lineage)¶
The offline counterpart to read_ncbi_lineage: walks a taxdump tree (read internally
via read_ncbi_taxdump) from each taxon up to the root and rank-collapses the path into
the same schema read_ncbi_lineage emits. Because the schema is identical, offline and
online are drop-in interchangeable.
Parameters:
- taxids (BIGINT[], optional, default NULL): the taxa to resolve. NULL collapses every live node (see the memory note below).
- source (optional, default NULL): passed straight to read_ncbi_taxdump — NULL auto-downloads/uses the cache; a directory or .tar.gz reads that instead
- refresh (BOOLEAN, optional, default false): passed to read_ncbi_taxdump
Output schema: identical to read_ncbi_lineage.
Behavior:
- Rank→column mapping (the single source of truth, mirrored from read_ncbi_lineage): superkingdom or domain → domain; phylum/class/order/family/genus/species/strain → their like-named columns; all other ranks (clade, subspecies, no rank, …) are dropped. Absent ranks are NULL in their column but rendered empty (e.g. p__) in the formatted lineage.
- A requested taxid that is not a live node produces no row (same omission semantics as read_ncbi_lineage; remap first with read_ncbi_taxdump_merged if a taxid may be retired).
- The taxdump is parsed once per call, regardless of how many taxids are requested.
Examples:
-- Same call shape and schema as read_ncbi_lineage, but offline over the cached dump
SELECT * FROM taxonomy_lineage(taxids := [562, 9606]);
-- Read from an extracted dump directory instead of the default cache
SELECT taxid, lineage
FROM taxonomy_lineage(taxids := [562], source := '/data/taxonomy/');
-- Attach lineages to sequence metadata by taxonomy_id
SELECT m.accession, l.lineage
FROM read_ncbi(['NC_001416.1', 'NC_000913.3']) m
JOIN taxonomy_lineage(source := '/data/taxonomy/') l ON l.taxid = m.taxonomy_id;
Notes:
- Memory: calling taxonomy_lineage() with taxids := NULL over the full NCBI tree materializes a lineage for every one of ~2.9M nodes and is memory-heavy (tens of GB peak). For typical use, always pass taxids := [...] — resolving thousands of taxids is fast and light. The unfiltered form is intended for whole-taxonomy exports on machines with ample RAM.