
Staged, sequential ingestion of wide measurement tables
Source:R/wide_measurement.R
load_wide_measurement.RdUnpivoting a wide table (PCORnet vital, flowsheets, device streams) with one giant uncommitted
UNION ALL materializes the whole result in DuckDB's append buffer and can exhaust RAM. This function
(a) stages the source once into a keyed intermediate table (integer primary key, values already cast to
DOUBLE, dates already normalized with vectorized_strptime()) and (b) inserts into measurement one
concept at a time, each pass in its own committed transaction, applying per-measurement plausibility
bounds. Peak memory is one column's worth of rows and a failed pass loses only that pass.
Mirror of omop_etl.wide_measurement.load_wide_measurement in Python.
Usage
load_wide_measurement(
con,
source,
concept_mapping,
person_col = "PATID",
date_col = "MEASURE_DATE",
time_col = "MEASURE_TIME",
visit_col = "ENCOUNTERID",
staged_table_name = "_staged_wide_measurement",
batch_execution_mode = c("sequential", "single"),
value_plausibility_filters = NULL,
person_id_is_cdm_id = FALSE,
measurement_type_concept_id = 32817L,
target_table = "measurement",
datetime_formats = NULL,
datetime_on_error = "null",
keep_staged = FALSE,
missing_columns = c("raise", "skip"),
coalesce_columns = "auto"
)Arguments
- con
DuckDB DBI connection holding the OMOP CDM (
person,visit_occurrence,measurement).- source
Table / view name, CSV / TSV / Parquet path, or a parenthesized query.
- concept_mapping
Named list
source_column -> list(concept_id, loinc, unit_concept_id, unit). A bare number is shorthand forlist(concept_id = n). Whenconcept_idis absent theloinccode is resolved throughconcept/concept_relationship. See DEFAULT_VITAL_CONCEPT_MAPPING.- person_col, date_col, time_col, visit_col
Source column names (case-insensitive);
time_colandvisit_colmay beNULL.- staged_table_name
Name of the intermediate table (integer primary key
stage_id).- batch_execution_mode
"sequential"(default; one committed single-concept insert per pass) or"single"(all passes in one transaction, committed at the end; only for small inputs).- value_plausibility_filters
Named list
source_column -> c(min, max)of inclusive clinical bounds; either bound may beNA. Out-of-range values are dropped and counted. Amin/maxinside a mapping entry is used when the column has no filter here. See DEFAULT_VITAL_PLAUSIBILITY_FILTERS.- person_id_is_cdm_id
Treat
person_colasperson.person_idinstead of the source patient id (matched toperson.person_source_value).- measurement_type_concept_id
Type concept stamped on every row.
- target_table
Destination (a
measurement-shaped table).- datetime_formats, datetime_on_error
Passed to
vectorized_strptime().- keep_staged
Keep the staging table after loading (default: drop it).
- missing_columns
"raise"(default) if a mapped column is absent from the source, or"skip"to ignore it (useful with DEFAULT_VITAL_CONCEPT_MAPPING on partial extracts).- coalesce_columns
Source columns that carry the same measure (e.g. PCORnet
BMIandORIGINAL_BMI) and must yield ONE measurement row per source row instead of one each.list(c("BMI", "ORIGINAL_BMI"))lists a precedence group: the first column with a value inside its plausibility bounds wins, later columns only fill gaps."auto"(default) builds a group, inconcept_mappingorder, from every set of columns sharing aconcept_id;NULLdisables coalescing (one row per column, as in 0.5.7). Every column of a group must map to the sameconcept_id.
Value
A data frame with one row per source column: source_column, concept_id, rows_non_null,
rows_out_of_range, rows_unmatched_person, rows_inserted, coalesced_into. A column folded into an
earlier one reports rows_inserted = 0 and the primary column's name in coalesced_into; the primary's
counts cover the whole group.