OHDSI Home | Forums | Wiki | Github

Multiple events per one cost

We have now some NDC codes that can’t be mapped to one standard concept because they don’t have enough attributes (we don’t know what is the exact Dose Form in this case)
FALESSA - levonorgestrel and ethinyl estradiol kit
So in OMOP vocabulary this one is mapped to two ingredients.

I like Gowtham’s idea:

So, to be in line with this, probably we need forbid to create multiple Maps to relationships for Drugs.
Instead

  • build ‘Is a’ relationships to Ethinyl Estradiol and Levonorgestrel.
  • keep the concepts non-standard
  • when ETL build custom concepts given concept will be mapped to (we can’t create them in the official release, because they violate the standard drug concept attribute model).

Ugly, but I don’t see better solution for now. So I want to hear from others.

1 Like

Splitting one record to two records makes health utilization and health economic analysis difficult. The only other way is the split record, but have a field in every omop table that says this was a ‘split’ record - and to only use the one of the split record. e.g. if FALESSA - levonorgestrel and ethinyl estradiol kit is split to two standard concept i.e. two records in drug_exposure; then we have an indicator field in drug_exposure that says split_provenance_concept_id and have concept_id to say ‘first’, ‘second’.

That a very interesting topic. It gets harder as there are things that the vocabulary team cannot control. When it comes to NDC, some decisions like not mapping to 2 can be made. But when it comes to the source drug data that get mapped to whatever exists in the official vocabs, it’s much harder. Say, you have a local drug in a free text (and we see it all the time), which can either be mapped to ingredients or remain unmapped, we would prefer to map it to something so that at least some information about drug exposures is preserved.
So, my question is: shouldn’t the cost be attached to visit? Or, if no visit exists, to a newly created ‘prescription/administration’ visit? Overall, it feels that the cost tables can handle adjustments since they are not that matured right now. Gowtham, what would you think? I bet there are other cases besides drugs that causes inflation of tables.

Just theoretical idea - Post-coordination.
Something like that:
Drug_exposure.postcoordination_concept_id
POSTCOORDINATION table:
postcoordination_concept_id | relationship_id | attribute_id
Estradiol_and_Levonorgestrel | Is a | Estradiol
Estradiol_and_Levonorgestrel | Is a | Levonorgestrel

Nobody will do that at least for now, but this can simplify a lot of cases like this.

Another idea - allow the combination of ingredients to be a standard concept.
Nobody will do

Actually I have another idea :slight_smile:
What if instead of the cost.cost_event_id field we will use another identifier to link events and costs.
For example, add cost_source_event_id field (or another more proper name) to event and cost tables. So several records from event table will have same cost_source_event_id.
Plain example:
cost:
cost_id — cost — cost_source_event_id
1 — $40 primary payer — 1
2 — $30 secondary payer — 1

drug_exposure:
drug_exposure_id — drug_concept_id — cost_source_event_id
1 — ingridient1 — 1
2 — ingridient2 — 1

1 Like

Yes - that would be perfect. If all OMOP tables have visit_occurrence_id as a required FK - it would simply. If there is no formal visit - we need to create pseudo visits to ensure referential integrity

Are you trying a many-to-many link here?

Why would that help? In one pharmacy visit you have more than one prescription drug.

Wait. Things that cost money usually we don’t split. Reason is that they tend to be clean (otherwise there would be endless discussions wiht the payers). But if there are a few - why wouldn’t we put the link from event to cost from the cost to the event tables? That way we could do many to one. Thoughts?

Yes - but more than prescription drug maybe collected in one visit. So, we will have 1 visit_occurrence_id record to many drug_exposure_id records. Visit_detail is another option. In US claims there is claim header/summary and claim detail/line. They may be mapped as follows.

Claim header --> visit_occurrence_id
Claim detail record --> visit_detail_id

Right now we allow linking from drug_exposure table to cost; from procedure_occurrence to cost. This is not a good relational database design. Instead if we force pseudo-visit records when visit records dont exist i.e. visit_occurrence_id and visit_detail_id for records that only have drug_exposure_id record: then we can have 1:many relationship between visit record and drug_exposure record; but 1:1 relationship between visit_*_id and cost_id.

We had discussed this design option in CDM workgroup - but I think we were worried that we would create row records unnecessarily and very large tables.

Well, yes. We know that several cost records might be linked to event. And according to the example of FALESSA - levonorgestrel and ethinyl estradiol kit several event records might be linked to cost table. So we might have m:m link.

1 Like

@Alexandra_Orlova:

Well, this is a weird example. This Falessa thing seems to have many incarnations:

  • It doesn’t exist as a brand name in RxNorm/Ex
  • The NDC code is valid, and it says it is a norgestrel/estradiol kit, which sounds like a contraceptive pack to me. So, there are such packs in the dictionary. But not Falessa.
  • There is an SPL FALESSA, but that one is not linked to the NDC, but to a bunch of completely unrelated ingredients
  • If you Google Falessa it is listed as a folic acid replacement drug

@aostropolets - can you take a look what’s going on?

At any rate, this is one drug, and should not cause splitting into different record. However, I understand that this will happen sometimes, and we need a solution. Need to think about that.

What about creating 2 bill + concepts with relationships ‘Is a’?
It is a solution when we resolve terminology issues in the vocabulary (where it should be resolved!), not CDM.
Note, we can’t keep any combination (if it’s even has correct attributes) as a standard concept, if this combination comes from some medical notes, let’s say, so we can’t keep this in OHDSI vocabulary. That’s why we create 2 bill+ concepts for this.

Probably adding of RxNorm’s multiple ingredient class as Standard concepts to be a part of a Drug domain hierarchy would be a more general solution than 2 bil+ concepts.
Will look into them.

Wait: Didn’t we say we will bring in MINs (RxNorm multiple ingredients)? That would solve this particular problem. But we still have the one-to-many mappings, and if the one has cost associated then how much goes to each component?

That would be a clandestine Extension solution. Can’t do that if it involves public vocabularies. 2B-Concepts are for local private ones.

Sure, I’ll take a look at it. Nevertheless, MINs won’t solve all problems. If people map to multiple standard concepts (and they do) this issue will keep re-occurring in multiple domains. Creating pseudo-visits will solve everything though.

But it will create pseudo-visits. When did you last attend a “pseudo-visit”? :slight_smile:

I agree, the MINs will solve this case, but not the general problem that the cost cannot be assigned to the “many” records easily in one-to-many mappings. I’d go for Extension Concepts. But then we need a proper way to create and manage them.

Do you mean
2B-Concepts are for local private ones?

Real ones.

Should we initiate MIN case adding to OMOP?

Even adding both RxNorm MIN class and RxNorm Extension existing ingredient combinations will not resolve the NDC issue completely. It looks like we need to add new ingredient combinations anyway.

Please find queries inside:

Among 82 NDC codes with 1-to-many mapping:
SELECT DISTINCT c1.concept_id
FROM concept c1

JOIN concept_relationship cr1
ON c1.concept_id = cr1.concept_id_1 AND cr1.relationship_id = 'Maps to' AND cr1.invalid_reason IS NULL

JOIN concept c2
ON cr1.concept_id_2 = c2.concept_id AND c2.standard_concept = 'S' AND c2.invalid_reason IS NULL

WHERE c1.vocabulary_id = 'NDC'
GROUP BY c1.concept_id
HAVING count(DISTINCT c2.concept_id) > 1
ORDER BY c1.concept_id
There are just 16 with appropriate drug forms and likely MINs
    with all_ndc as (
select c1.concept_id as ndc_id,
       c1.concept_name as ndc_name,
       array_agg(distinct ds.ingredient_concept_id order by ds.ingredient_concept_id) ndc_arr
from concept c1
join concept_relationship r on r.concept_id_1 = c1.concept_id and r.invalid_reason is null and r.relationship_id = 'Maps to'
join drug_strength ds on ds.drug_concept_id = r.concept_id_2
where c1.vocabulary_id = 'NDC'
and c1.concept_id in (SELECT DISTINCT c1.concept_id
                        FROM concept c1

                                 JOIN concept_relationship cr1
                                      ON c1.concept_id = cr1.concept_id_1 AND cr1.relationship_id = 'Maps to' AND cr1.invalid_reason IS NULL

                                 JOIN concept c2
                                      ON cr1.concept_id_2 = c2.concept_id AND c2.standard_concept = 'S' AND c2.invalid_reason IS NULL

                        WHERE c1.vocabulary_id = 'NDC'

                        GROUP BY c1.concept_id
                        HAVING count(DISTINCT c2.concept_id) > 1
                        ORDER BY c1.concept_id
    )
group by c1.concept_id, c1.concept_name
)

select distinct n.ndc_id, n.ndc_name, c3.concept_id as rx_id, c3.concept_name as rx_name, cl_drugs.form_id, cl_drugs.form_name
from all_ndc n
join (
	select c1.concept_id as form_id,
	       c1.concept_name as form_name,
	       array_agg(ds.ingredient_concept_id order by ds.ingredient_concept_id) drugs_arr
    from concept c1
    join drug_strength ds on ds.drug_concept_id = c1.concept_id
    where c1.vocabulary_id like 'Rx%'
    and c1.concept_class_id = 'Clinical Drug Form'
    group by c1.concept_id, c1.concept_name

) cl_drugs on cl_drugs.drugs_arr=n.ndc_arr
join concept_relationship r3 on n.ndc_id = r3.concept_id_1 and r3.invalid_reason is null and r3.relationship_id = 'Maps to'
join concept c3 on r3.concept_id_2 = c3.concept_id
order by 1,2,3,4,5,6
The rest 66 of them have no such. Most of them are multivitamins, but still
    with all_ndc as (
select c1.concept_id as ndc_id,
       c1.concept_name as ndc_name,
       array_agg(distinct ds.ingredient_concept_id order by ds.ingredient_concept_id) ndc_arr
from concept c1
join concept_relationship r on r.concept_id_1 = c1.concept_id and r.invalid_reason is null and r.relationship_id = 'Maps to'
join drug_strength ds on ds.drug_concept_id = r.concept_id_2
where c1.vocabulary_id = 'NDC'
and c1.concept_id in (SELECT DISTINCT c1.concept_id
                        FROM concept c1

                                 JOIN concept_relationship cr1
                                      ON c1.concept_id = cr1.concept_id_1 AND cr1.relationship_id = 'Maps to' AND cr1.invalid_reason IS NULL

                                 JOIN concept c2
                                      ON cr1.concept_id_2 = c2.concept_id AND c2.standard_concept = 'S' AND c2.invalid_reason IS NULL

                        WHERE c1.vocabulary_id = 'NDC'

                        GROUP BY c1.concept_id
                        HAVING count(DISTINCT c2.concept_id) > 1
                        ORDER BY c1.concept_id
    )
group by c1.concept_id, c1.concept_name
)

select distinct n.ndc_id, n.ndc_name, c3.concept_id as rx_id, c3.concept_name as rx_name, cl_drugs.form_id, cl_drugs.form_name
from all_ndc n
left join (
	select c1.concept_id as form_id,
	       c1.concept_name as form_name,
	       array_agg(ds.ingredient_concept_id order by ds.ingredient_concept_id) drugs_arr
    from concept c1
    join drug_strength ds on ds.drug_concept_id = c1.concept_id
    where c1.vocabulary_id like 'Rx%'
    and c1.concept_class_id = 'Clinical Drug Form'
    group by c1.concept_id, c1.concept_name

) cl_drugs on cl_drugs.drugs_arr=n.ndc_arr
join concept_relationship r3 on n.ndc_id = r3.concept_id_1 and r3.invalid_reason is null and r3.relationship_id = 'Maps to'
join concept c3 on r3.concept_id_2 = c3.concept_id
where form_id is null
order by 1,2,3,4,5,6

;

t