Day 1 · SQL Code Snippets
Ready-to-run queries for exploring the OMOP CDM and standardized vocabularies. Adjust schema prefixes (
cdm.) to match your site's configuration.
1. Explore the concept table
Find a concept by name
SELECT concept_id,
concept_name,
domain_id,
vocabulary_id,
concept_class_id,
standard_concept,
concept_code
FROM cdm.concept
WHERE LOWER(concept_name) LIKE '%type 2 diabetes%'
ORDER BY standard_concept DESC, concept_name;
standard_concept = 'S'→ standard concept;NULL→ non-standard (source) concept.
Find a concept by exact concept_id
List all vocabularies in your CDM
SELECT vocabulary_id,
vocabulary_name,
vocabulary_reference,
vocabulary_version
FROM cdm.vocabulary
ORDER BY vocabulary_id;
Count concepts by domain and standard flag
SELECT domain_id,
standard_concept,
COUNT(*) AS concept_count
FROM cdm.concept
GROUP BY domain_id, standard_concept
ORDER BY domain_id, standard_concept;
2. Explore the concept_relationship table
Find how a non-standard code maps to a standard concept
-- Replace 45548499 with any non-standard concept_id (e.g., an ICD-10-CM code)
SELECT cr.concept_id_1,
c1.concept_name AS source_concept,
c1.vocabulary_id AS source_vocab,
cr.relationship_id,
cr.concept_id_2,
c2.concept_name AS target_concept,
c2.standard_concept
FROM cdm.concept_relationship cr
JOIN cdm.concept c1 ON cr.concept_id_1 = c1.concept_id
JOIN cdm.concept c2 ON cr.concept_id_2 = c2.concept_id
WHERE cr.concept_id_1 = 45548499
AND cr.relationship_id = 'Maps to'
AND cr.invalid_reason IS NULL;
See all relationships for a standard concept
SELECT cr.relationship_id,
c2.concept_id,
c2.concept_name,
c2.vocabulary_id,
c2.domain_id
FROM cdm.concept_relationship cr
JOIN cdm.concept c2 ON cr.concept_id_2 = c2.concept_id
WHERE cr.concept_id_1 = 201826 -- Type 2 diabetes mellitus
AND cr.invalid_reason IS NULL
ORDER BY cr.relationship_id;
Common
relationship_idvalues:'Maps to','Is a','Subsumes','Has ancestor','Maps to value'.
Find all ICD-10-CM codes that map to a given SNOMED concept
SELECT c_source.concept_id,
c_source.concept_code,
c_source.concept_name,
c_source.vocabulary_id
FROM cdm.concept_relationship cr
JOIN cdm.concept c_source ON cr.concept_id_1 = c_source.concept_id
WHERE cr.concept_id_2 = 201826 -- target SNOMED concept
AND cr.relationship_id = 'Maps to'
AND c_source.vocabulary_id IN ('ICD10CM', 'ICD9CM')
AND cr.invalid_reason IS NULL;
3. Explore the concept_ancestor table
Find all descendants of a concept (for concept set building)
SELECT ca.descendant_concept_id,
c.concept_name,
c.vocabulary_id,
c.standard_concept,
ca.min_levels_of_separation,
ca.max_levels_of_separation
FROM cdm.concept_ancestor ca
JOIN cdm.concept c ON ca.descendant_concept_id = c.concept_id
WHERE ca.ancestor_concept_id = 21600381 -- Sulfonylureas (SNOMED ingredient class)
ORDER BY ca.min_levels_of_separation, c.concept_name;
Find all ancestors of a concept (traverse upward)
SELECT ca.ancestor_concept_id,
c.concept_name,
c.vocabulary_id,
ca.min_levels_of_separation
FROM cdm.concept_ancestor ca
JOIN cdm.concept c ON ca.ancestor_concept_id = c.concept_id
WHERE ca.descendant_concept_id = 1503297 -- Metformin
AND ca.min_levels_of_separation > 0
ORDER BY ca.min_levels_of_separation;
4. Explore clinical domain tables
Count patients in the person table
Demographics summary
SELECT year_of_birth,
gender_concept_id,
g.concept_name AS gender,
race_concept_id,
r.concept_name AS race,
COUNT(*) AS n
FROM cdm.person p
LEFT JOIN cdm.concept g ON p.gender_concept_id = g.concept_id
LEFT JOIN cdm.concept r ON p.race_concept_id = r.concept_id
GROUP BY year_of_birth, gender_concept_id, g.concept_name, race_concept_id, r.concept_name
ORDER BY year_of_birth DESC;
Count condition occurrences by standard concept
SELECT co.condition_concept_id,
c.concept_name,
COUNT(*) AS occurrence_count,
COUNT(DISTINCT co.person_id) AS person_count
FROM cdm.condition_occurrence co
JOIN cdm.concept c ON co.condition_concept_id = c.concept_id
WHERE c.standard_concept = 'S'
GROUP BY co.condition_concept_id, c.concept_name
ORDER BY person_count DESC
LIMIT 25;
Find drug exposures for a drug (using ancestor join)
-- Count metformin exposures (includes all descendants via concept_ancestor)
SELECT COUNT(*) AS total_exposures,
COUNT(DISTINCT de.person_id) AS unique_patients
FROM cdm.drug_exposure de
JOIN cdm.concept_ancestor ca
ON ca.descendant_concept_id = de.drug_concept_id
WHERE ca.ancestor_concept_id = 1503297; -- Metformin ingredient
Observation period summary
SELECT
COUNT(DISTINCT person_id) AS persons_with_obs,
ROUND(AVG(
DATEDIFF(observation_period_end_date, observation_period_start_date)
)) AS avg_obs_days,
MIN(observation_period_start_date) AS earliest_start,
MAX(observation_period_end_date) AS latest_end
FROM cdm.observation_period;
5. Quick data quality spot checks
Find records with concept_id = 0 (unmapped / non-standard)
-- Condition occurrences with no standard concept
SELECT COUNT(*) AS unmapped_conditions
FROM cdm.condition_occurrence
WHERE condition_concept_id = 0;
-- Drug exposures with no standard concept
SELECT COUNT(*) AS unmapped_drugs
FROM cdm.drug_exposure
WHERE drug_concept_id = 0;
Check for implausible birth years
SELECT year_of_birth, COUNT(*) AS n
FROM cdm.person
WHERE year_of_birth < 1900 OR year_of_birth > YEAR(CURRENT_DATE)
GROUP BY year_of_birth
ORDER BY year_of_birth;
Check observation period coverage
-- Persons with no observation period (should be 0)
SELECT COUNT(*) AS persons_without_obs
FROM cdm.person p
WHERE NOT EXISTS (
SELECT 1
FROM cdm.observation_period op
WHERE op.person_id = p.person_id
);
Back to Day 1 module · Back to Day 1 exercise · OMOP SQL Cheat Sheet