Table name: stem_table
The STEM table is a staging area where source codes like ICD9 codes will first be mapped to concept_ids. The STEM table itself is an amalgamation of the OMOP event tables to facilitate record movement. This means that all fields present across the OMOP event tables are present in the STEM table. After a record is mapped and staged, the domain of the concept_id dictates which OMOP table (Condition_occurrence, Drug_exposure, Procedure_occurrence, Measurement, Observation, Device_exposure) the record will move to. Please see the STEM -> CDM mapping files for a description of which STEM fields move to which STEM tables.
Key conventions
-
Labs records are not considered visits so therefore all VISIT_DETAIL_ID and VISIT_OCCURRENCE_ID fields are NULL.
- Lab result in LAB is stored in three fields: ABNORMAL, RESULT (numeric) and RESLTCAT (character). Numeric results can be in both RESULT and RESLTCAT. RESULT usually has the following values if the lab result is string: 0 or large negative value (<-999999.99999). ABNORMAL is the abnormal indicator set by the lab vendors: ‘A’ means “abnormal”, ‘N’ means “normal”, ‘H’ means “Above the normal range”, ‘L’ means “Below the normal range”, ‘+’ means “Positive” and ‘-’ means “Negative”.
- Use the following to set VALUE_SOURCE_VALUE and VALUE_AS_CONCEPT_ID:
/*Result as string*/ VALUE_AS_STRING = CATS(RESLTCAT); /*Result as concept code*/ IF UPCASE(VALUE_AS_STRING) ='LOW' OR ABNORMAL ='L' THEN VALUE_AS_CONCEPT_ID = 4267416; ELSE IF UPCASE(VALUE_AS_STRING) ='HIG' OR ABNORMAL ='H' THEN VALUE_AS_CONCEPT_ID =4328749; ELSE IF UPCASE(VALUE_AS_STRING) ='NRM' OR ABNORMAL ='N' THEN VALUE_AS_CONCEPT_ID =4069590; ELSE IF UPCASE(VALUE_AS_STRING) ='ABN' OR ABNORMAL ='A' THEN VALUE_AS_CONCEPT_ID =4135493; ELSE IF UPCASE(VALUE_AS_STRING) ='ABS' THEN VALUE_AS_CONCEPT_ID =4132135; ELSE IF UPCASE(VALUE_AS_STRING) ='PRS' THEN VALUE_AS_CONCEPT_ID =4181412; ELSE IF UPCASE(VALUE_AS_STRING) ='POS' OR ABNORMAL ='+' THEN VALUE_AS_CONCEPT_ID =9191; ELSE IF UPCASE(VALUE_AS_STRING) ='NEG' OR ABNORMAL ='-' THEN VALUE_AS_CONCEPT_ID =9189; ELSE IF UPCASE(VALUE_AS_STRING) IN ('FIN','FIR') THEN VALUE_AS_CONCEPT_ID =9188; ELSE IF UPCASE(VALUE_AS_STRING) ='NON' THEN VALUE_AS_CONCEPT_ID =9190; ELSE IF UPCASE(VALUE_AS_STRING) ='TRA' THEN VALUE_AS_CONCEPT_ID = 9192; IF RESULT > -999999.99999 THEN DO; /*Result as number*/ VALUE_AS_NUMBER = RESULT;END;
Reading from LAB
Destination Field | Source field | Logic | Comment field |
---|---|---|---|
DOMAIN_ID | - | - | This should be the domain_id of the standard concept in the CONCEPT_ID field. If a code is mapped to CONCEPT_ID 0, put the domain_id as Observation |
PERSON_ID | ENROLID | - | - |
VISIT_OCCURRENCE_ID | NULL | - | - |
VISIT_DETAIL_ID | NULL | - | - |
PROVIDER_ID | PROVID | - | - |
ID | - | System generated. | - |
CONCEPT_ID | LOINCCD | Use the Source-to-Standard Query.WHERE SOURCE_VOCABULARY_ID IN ('LOINC') AND TARGET_STANDARD_CONCEPT = 'S' AND TARGET_INVALID_REASON IS NULL | - |
SOURCE_VALUE | LOINCCD | The LOINCCD as it appears in the LAB table | - |
SOURCE_CONCEPT_ID | LOINCCD | Use the Source-to-Source Query.WHERE SOURCE_VOCABULARY_ID IN (‘LOINC’) AND TARGET_VOCABULARY_ID IN (‘LOINC’) | - |
TYPE_CONCEPT_ID | - | All rows will have CONCEPT_ID 32856 | 32856 = ‘Lab’ |
START_DATE | SVCDATE | - | - |
START_DATETIME | - | START_DATE + Midnight | - |
END_DATE | - | NULL | - |
END_DATETIME | - | NULL | - |
VERBATIM_END_DATE | - | NULL | - |
DAYS_SUPPLY | - | NULL | - |
DOSE_UNIT_SOURCE_VALUE | - | NULL | - |
LOT_NUMBER | - | NULL | - |
MODIFIER_CONCEPT_ID | - | NULL | - |
MODIFIER_SOURCE_VALUE | - | NULL | - |
OPERATOR_CONCEPT_ID | - | NULL | - |
QUANTITY | - | NULL | - |
RANGE_HIGH | REFHIGH | - | - |
RANGE_LOW | REFLOW | - | - |
REFILLS | - | NULL | - |
ROUTE_CONCEPT_ID | - | 0 | - |
ROUTE_SOURCE_VALUE | - | NULL | - |
SIG | - | NULL | - |
STOP_REASON | - | NULL | - |
UNIQUE_DEVICE_ID | - | NULL | - |
UNIT_CONCEPT_ID | RESUNIT | Use the Source-to-Standard Query. Filters: WHERE SOURCE_VOCABULARY_ID IN ('UCUM') AND TARGET_VOCABULARY_ID IN ('UCUM') AND TARGET_INVALID_REASON IS NULL If you do not get a map from UCUM use the JNJ_UNIT vocabulary. Set UNIT_CONCEPT_ID = NULL when the source unit value is NULL; Set UNIT_CONCEPT_ID = 0 when source unit value is not NULL but doesn’t have a mapping | - |
UNIT_SOURCE_VALUE | RESUNIT | RESUNIT as it appears in the LAB table | - |
VALUE_AS_CONCEPT_ID | RESLTCAT ABNORMAL | Refer to logic above for defining this field. After assigning the above logic, then map RESLTCAT to a Standard Concept using the SOURCE_TO_STANDARD query with the filter LOINC_CD WHERE SOURCE_VOCABULARY_ID IN (‘LOINC’) AND TARGET_STANDARD_CONCEPT =’S’ AND TARGET_INVALID_REASON IS NULL, mapping to SOURCE_CODE_DESCRIPTION instead of SOURCE_CODE | - |
VALUE_AS_NUMBER | RESULT | Put any numerical values in the RESULT field here. All values in the RESULT field as they show up in the native will be present in VALUE_SOURCE_VALUE field of the CDM. For the following LOINCs (3142-7, 29463-7, 3141-9) if the RESULT > 100000 and the last digits are 0000 and RESUNIT = ‘LBS’, trim the last four digits 0000. | - |
VALUE_AS_STRING | RESULT RESLTCAT | Refer to logic above for defining this field. | - |
VALUE_SOURCE_VALUE | RESULT_RESLTCAT | Concatenate RESULT, RESLTCAT, and ABNORMAL with ‘;’ between. | - |
ANATOMIC_SITE_CONCEPT_ID | - | 0 | - |
DISEASE_STATUS_CONCEPT_ID | - | 0 | - |
SPECIMIN_SOURCE_ID | - | NULL | - |
ANATOMIC_SITE_SOURCE_VALUE | - | NULL | - |
DISEASE_STATUS_SOURCE_VALUE | - | NULL | - |
CONDITION_STATUS_CONCEPT_ID | - | 0 | - |
CONDITION_STATUS_SOURCE_VALUE | - | NULL | - |
EVENT_ID | - | NULL | - |
EVENT_FIELD_CONCEPT_ID | - | 0 | - |
VALUE_AS_DATETIME | - | NULL | - |
QUALIFIER_CONCEPT_ID | - | 0 | - |
QUALIFIER_SOURCE_VALUE | - | NULL | - |
Change Log
September 29, 2022
- Units rule changed:
- Set UNIT_CONCEPT_ID = NULL when the source unit value is NULL
- Set UNIT_CONCEPT_ID =0 when source unit value is not NULL but doesn’t have a mapping
July 15, 2021
- Mapping added to VALUE_AS_CONCEPT_ID
August 9, 2021
- VALUE_SOURCE_VALUE is now created by concatenating result, resultcat, and abnormal
July 13, 2021
- Changed logic referring to how lab result source values should be represented in the CDM:
- Removed decision to not show a RESULT of 0 in VALUE_AS_NUMBER. This was originally embedded in the sql statement showing how to assign VALUE_AS_CONCEPT_ID. The final line was
IF RESULT NE to 0 or RESULT > -999999.99999 THEN DO; VALUE_AS_NUMBER = RESULT;END;
. Instead, it now readsIF RESULT > -999999.99999 THEN DO; VALUE_AS_NUMBER = RESULT;END;
- Introduced concatenation in VALUE_SOURCE_VALUE. The instructions now read: If RESLTCAT is not NULL then concatenate RESULT and RESLTCAT with ‘_’ between. If RESLTCAT is NULL then just put the value from RESULT as it appears in the LAB table.
- Removed decision to not show a RESULT of 0 in VALUE_AS_NUMBER. This was originally embedded in the sql statement showing how to assign VALUE_AS_CONCEPT_ID. The final line was
June 10, 2021
- Labs will not create visits on their own so that logic was removed.
June 9, 2021
-
Updated type concept
-
Removed the following logic:
- LOINCs
- Valid LOINC codes have the following layouts #-#, ##-#, ###-#, ####-#, and #####-# .
- When mapping to valid LOINCs in the OMOP Vocabulary there are a few invalid LOINC codes. Implementing a check for the second to last character is a ‘-‘ensures you pull a valid LOINC from the VOCABULARY.
- Only use records with SVCDATE that fall within an OBSERVATION_PERIOD available for this person.
- LOINCs