-
Notifications
You must be signed in to change notification settings - Fork 75
/
Copy pathBuildRxE.sql
6884 lines (6443 loc) · 215 KB
/
BuildRxE.sql
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
/**************************************************************************
* Copyright 2016 Observational Health Data Sciences and Informatics (OHDSI)
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* Authors: Christian Reich
* Date: 2016-2020
**************************************************************************/
/***************************************************************************
To do list:
- Possible excipient,
- mEq to mmol,
- other funny units,
- use dfg_id for best pattern search
- don't use quantifieds for r_uds, use the equivalent non-quantified one, otherwise rounding error possible
***************************************************************************/
/******************************************************************************
* This script creates a new drug vocabulary in the OMOP Standard Vocabularies *
* The new drug vocabulary must be provided in the format described in *
* http://www.ohdsi.org/web/wiki/doku.php?id=documentation:international_drugs *
* The processing is also described there. The following tables are required: *
* drug_concept_stage, internal_relationship_stage, relationship_to_concept, *
* pc_stage, ds_stage. *
* Records that have no concept_code in the source should *
* receive autogenerated ones in the format 'OMOP' plus a running number. *
* The tables concept, concept_relationship, concept_ancestor and *
* drug_strength need to be locally availabe. *
*******************************************************************************/
CREATE OR REPLACE FUNCTION vocabulary_pack.BuildRxE ()
RETURNS void AS
$BODY$
/*Usage:
DO $_$
BEGIN
PERFORM vocabulary_pack.BuildRxE();
END $_$;
*/
BEGIN
/** IMPORTANT **/
/* Add the latest_update and version information to the VOCABULARY table **/
/*quick QA for input tables*/
--drug_concept_stage
ALTER TABLE drug_concept_stage
ADD CONSTRAINT tmp_dcs_name CHECK (concept_name IS NOT NULL AND concept_name<>''),
ADD CONSTRAINT tmp_dcs_domain CHECK (domain_id IS NOT NULL AND domain_id<>''),
ADD CONSTRAINT tmp_dcs_vocabulary CHECK (vocabulary_id IS NOT NULL AND vocabulary_id<>''),
ADD CONSTRAINT tmp_dcs_class CHECK (concept_class_id IS NOT NULL AND concept_class_id<>''),
ADD CONSTRAINT tmp_dcs_code CHECK (concept_code IS NOT NULL AND concept_code<>''),
ADD CONSTRAINT tmp_dcs_reason CHECK (COALESCE(invalid_reason,'D') in ('D','U'));
ALTER TABLE drug_concept_stage
DROP CONSTRAINT tmp_dcs_name,
DROP CONSTRAINT tmp_dcs_domain,
DROP CONSTRAINT tmp_dcs_vocabulary,
DROP CONSTRAINT tmp_dcs_class,
DROP CONSTRAINT tmp_dcs_code,
DROP CONSTRAINT tmp_dcs_reason;
--internal_relationship_stage
ALTER TABLE internal_relationship_stage
ADD CONSTRAINT tmp_irs_code1 CHECK (concept_code_1 IS NOT NULL AND concept_code_1<>''),
ADD CONSTRAINT tmp_irs_code2 CHECK (concept_code_2 IS NOT NULL AND concept_code_2<>'');
ALTER TABLE internal_relationship_stage
DROP CONSTRAINT tmp_irs_code1,
DROP CONSTRAINT tmp_irs_code2;
--relationship_to_concept
ALTER TABLE relationship_to_concept
ADD CONSTRAINT tmp_rtc_code1 CHECK (concept_code_1 IS NOT NULL AND concept_code_1<>''),
ADD CONSTRAINT tmp_rtc_vocabulary1 CHECK (vocabulary_id_1 IS NOT NULL AND vocabulary_id_1<>''),
ADD CONSTRAINT tmp_rtc_id2 CHECK (concept_id_2 IS NOT NULL),
ADD CONSTRAINT tmp_rtc_float CHECK (pg_typeof(conversion_factor)='numeric'::regtype),
ADD CONSTRAINT tmp_rtc_int2 CHECK (pg_typeof(precedence)='smallint'::regtype);
ALTER TABLE relationship_to_concept
DROP CONSTRAINT tmp_rtc_code1,
DROP CONSTRAINT tmp_rtc_vocabulary1,
DROP CONSTRAINT tmp_rtc_id2,
DROP CONSTRAINT tmp_rtc_float,
DROP CONSTRAINT tmp_rtc_int2;
--pc_stage
ALTER TABLE pc_stage
ADD CONSTRAINT tmp_pcs_pack CHECK (pack_concept_code IS NOT NULL AND pack_concept_code<>''),
ADD CONSTRAINT tmp_pcs_drug CHECK (drug_concept_code IS NOT NULL AND drug_concept_code<>''),
ADD CONSTRAINT tmp_pcs_amount_int2 CHECK (pg_typeof(amount)='smallint'::regtype),
ADD CONSTRAINT tmp_pcs_bx_int2 CHECK (pg_typeof(box_size)='smallint'::regtype);
ALTER TABLE pc_stage
DROP CONSTRAINT tmp_pcs_pack,
DROP CONSTRAINT tmp_pcs_drug,
DROP CONSTRAINT tmp_pcs_amount_int2,
DROP CONSTRAINT tmp_pcs_bx_int2;
--ds_stage
ALTER TABLE ds_stage
ADD CONSTRAINT tmp_dss_drug CHECK (drug_concept_code IS NOT NULL AND drug_concept_code<>''),
ADD CONSTRAINT tmp_dss_ing CHECK (ingredient_concept_code IS NOT NULL AND ingredient_concept_code<>''),
ADD CONSTRAINT tmp_dss_float1 CHECK (pg_typeof(amount_value)='numeric'::regtype),
ADD CONSTRAINT tmp_dss_float2 CHECK (pg_typeof(numerator_value)='numeric'::regtype),
ADD CONSTRAINT tmp_dss_float3 CHECK (pg_typeof(denominator_value)='numeric'::regtype),
ADD CONSTRAINT tmp_dss_int2 CHECK (pg_typeof(box_size)='smallint'::regtype);
ALTER TABLE ds_stage
DROP CONSTRAINT tmp_dss_drug,
DROP CONSTRAINT tmp_dss_ing,
DROP CONSTRAINT tmp_dss_float1,
DROP CONSTRAINT tmp_dss_float2,
DROP CONSTRAINT tmp_dss_float3,
DROP CONSTRAINT tmp_dss_int2;
/*end QA*/
-- Clean version of r_to_c
DROP TABLE IF EXISTS r_to_c;
--CREATE OR replace VIEW r_to_c AS
CREATE UNLOGGED TABLE r_to_c AS
SELECT r.*
FROM relationship_to_concept r
JOIN concept c ON c.concept_id = r.concept_id_2
AND c.vocabulary_id IN (
'RxNorm',
'RxNorm Extension',
'UCUM'
)
;
CREATE INDEX idx_rtc ON r_to_c (concept_code_1, concept_id_2);
ANALYZE r_to_c;
/*****************************************************************************************************************************************************
* 1. Prepare drug components for new vocabularies: Create unique list and for each drug enumerate. This allows to create a single row for each drug. *
*****************************************************************************************************************************************************/
-- Sequence for unique q_ds
DROP SEQUENCE IF EXISTS ds_seq;
CREATE SEQUENCE ds_seq INCREMENT BY 1 START WITH 1 NO CYCLE CACHE 20;
-- Sequence for temporary XXX concept codes
DROP SEQUENCE IF EXISTS xxx_seq;
CREATE SEQUENCE xxx_seq INCREMENT BY 1 START WITH 1 NO CYCLE CACHE 20;
-- Sequence for non-existing concept_ids for extension concepts
DROP SEQUENCE IF EXISTS extension_id;
CREATE SEQUENCE extension_id INCREMENT BY -1 START WITH -1 NO CYCLE CACHE 20;
/*****************************
* 2. Collect atributes for q *
*****************************/
-- Create table with all drug concept codes linked to the codes of the ingredients (rather than full dose components)
DROP TABLE IF EXISTS q_ing;
CREATE UNLOGGED TABLE q_ing AS
SELECT dcs1.concept_code AS concept_code,
dcs2.concept_code AS i_code
FROM drug_concept_stage dcs1
JOIN internal_relationship_stage irs ON irs.concept_code_1 = dcs1.concept_code
JOIN drug_concept_stage dcs2 ON dcs2.concept_code = irs.concept_code_2
AND dcs2.concept_class_id = 'Ingredient'
WHERE dcs1.concept_class_id = 'Drug Product'
AND dcs1.domain_id = 'Drug' -- Drug Products
UNION
SELECT drug_concept_code AS concept_code,
ingredient_concept_code AS i_code
FROM ds_stage; -- just in case, won't hurt if the internal_relationship table forgot something
-- Create distinct version of drug_strength in concentration notation (no quant).
-- Replace nulls with 0 and ' '
-- Create a rounded version of ds_stage
DROP TABLE IF EXISTS ds_rounded;
CREATE UNLOGGED TABLE ds_rounded AS
SELECT s0.drug_concept_code,
s0.ingredient_concept_code,
CASE s0.amount_value
WHEN 0
THEN 0
ELSE ROUND(s0.amount_value, (3 - FLOOR(LOG(s0.amount_value)) - 1)::INT)
END AS amount_value,
s0.amount_unit,
CASE s0.numerator_value
WHEN 0
THEN 0
ELSE ROUND(s0.numerator_value, (3 - FLOOR(LOG(s0.numerator_value)) - 1)::INT)
END AS numerator_value,
s0.numerator_unit,
s0.denominator_unit
FROM (
SELECT ds.drug_concept_code,
ds.ingredient_concept_code,
COALESCE(ds.amount_value, 0) AS amount_value,
COALESCE(ds.amount_unit, ' ') AS amount_unit,
CASE
WHEN rtc.concept_id_2 IN (
8554,
9325,
9324
)
THEN numerator_value -- % and homeopathics is already a fixed concentration, no need to adjust to volume
WHEN COALESCE(ds.numerator_value, 0) = 0
THEN 0
ELSE ds.numerator_value / COALESCE(ds.denominator_value, 1) -- turn into concentration as basis for comparison.
END AS numerator_value,
COALESCE(ds.numerator_unit, ' ') AS numerator_unit,
CASE -- denominator unit should be undefined for % and the homeopathics
WHEN rtc.concept_id_2 IN (
8554,
9325,
9324
)
THEN NULL -- % and homeopathics is already a fixed concentration, no need to adjust to volume
ELSE COALESCE(ds.denominator_unit, ' ')
END AS denominator_unit
FROM ds_stage ds
LEFT JOIN r_to_c rtc ON rtc.concept_code_1 = ds.numerator_unit
AND COALESCE(rtc.precedence, 1) = 1 -- to get the q version of % and homeopathics
) AS s0;
-- Create unique dose table
DROP TABLE IF EXISTS q_uds;
CREATE UNLOGGED TABLE q_uds (
ds_code VARCHAR(50),
ingredient_concept_code VARCHAR(50),
amount_value NUMERIC,
amount_unit VARCHAR(50),
numerator_value NUMERIC,
numerator_unit VARCHAR(50),
denominator_unit VARCHAR(50)
);
INSERT INTO q_uds
SELECT NEXTVAL('ds_seq')::VARCHAR AS ds_code,
q_ds.*
FROM (
SELECT DISTINCT ingredient_concept_code,
amount_value,
amount_unit,
numerator_value,
numerator_unit,
denominator_unit
FROM ds_rounded
ORDER BY ingredient_concept_code,
amount_value,
amount_unit,
numerator_value,
numerator_unit,
denominator_unit --just for sequence repeatability
) AS q_ds;
-- Create table with all drug concept codes linked to the above unique components
DROP TABLE IF EXISTS q_ds;
CREATE UNLOGGED TABLE q_ds AS
SELECT drug_concept_code AS concept_code,
ingredient_concept_code AS i_code,
DENSE_RANK() OVER (
ORDER BY ingredient_concept_code,
amount_value,
amount_unit,
numerator_value,
numerator_unit,
denominator_unit
)::VARCHAR AS ds_code,
denominator_unit AS quant_unit
FROM ds_rounded;
CREATE INDEX idx_q_ds_dscode ON q_ds (ds_code);
CREATE INDEX idx_q_ds_concode ON q_ds (concept_code);
ANALYZE q_ds;
-- Turn gases into percent if they are in mg/mg or mg/mL
UPDATE q_uds q
SET numerator_value = CASE
WHEN concept_id_2 = 8576
THEN numerator_value * 100
ELSE numerator_value / 10
END,
numerator_unit = (
SELECT concept_code_1
FROM r_to_c
WHERE concept_id_2 = 8554
AND precedence = 1
), -- set to percent
denominator_unit = NULL
FROM (
SELECT q2.ds_code,
rd.concept_id_2
FROM internal_relationship_stage irs
JOIN r_to_c rc ON rc.concept_code_1 = irs.concept_code_2
JOIN q_ds q1 ON q1.concept_code = irs.concept_code_1
JOIN q_uds q2 ON q2.ds_code = q1.ds_code
JOIN r_to_c rn ON rn.concept_code_1 = q2.numerator_unit
AND rn.precedence = 1 -- translate to Standard for numerator
JOIN r_to_c rd ON rd.concept_code_1 = q2.denominator_unit
AND rd.precedence = 1 -- translate to Standard for denominator
WHERE rc.concept_id_2 IN (
19082258,
40228366
) -- Gas for Inhalation, Gas
AND rn.concept_id_2 = 8576 /*mg*/
AND rd.concept_id_2 IN (
8576 /*mg*/,
8587 /*mL*/
)
) i
WHERE i.ds_code = q.ds_code;
-- Create table with the combination of components for each drug concept delimited by '-'
-- Contains both ingredient combos and ds combos. For Drug Forms d_combo=' '
DROP TABLE IF EXISTS q_combo;
CREATE UNLOGGED TABLE q_combo AS
SELECT concept_code,
STRING_AGG(i_code, '-' ORDER BY i_code) AS i_combo,
STRING_AGG(ds_code, '-' ORDER BY LPAD(ds_code,10,'0')) AS d_combo --LPAD for 'old' sorting when ds_code was an integer
FROM q_ds
GROUP BY concept_code;
-- Add Drug Forms, which have no entry in ds_stage. Shouldn't exist, unless there are singleton Drug Forms with no descendants.
-- build the i_combos from scratch, no equivalent to q_ds
INSERT INTO q_combo
SELECT dcs1.concept_code,
STRING_AGG(dcs2.concept_code, '-' ORDER BY dcs2.concept_code) AS i_combo,
' ' AS d_combo
FROM drug_concept_stage dcs1
JOIN internal_relationship_stage r ON r.concept_code_1 = dcs1.concept_code
JOIN drug_concept_stage dcs2 ON dcs2.concept_code = r.concept_code_2
AND dcs2.concept_class_id = 'Ingredient'
WHERE dcs1.concept_code IN (
SELECT concept_code
FROM drug_concept_stage dcs_int
WHERE dcs_int.domain_id = 'Drug'
AND dcs_int.concept_class_id = 'Drug Product'
EXCEPT
SELECT drug_concept_code
FROM ds_stage
)
AND NOT EXISTS (
SELECT 1
FROM q_combo q
WHERE q.concept_code = dcs1.concept_code
)
GROUP BY dcs1.concept_code;
CREATE INDEX idx_q_combo ON q_combo (concept_code);
ANALYZE q_combo;
-- Create table with Quantity Factor information for each drug (if exists), not rounded
DROP TABLE IF EXISTS q_quant;
CREATE UNLOGGED TABLE q_quant AS
SELECT DISTINCT drug_concept_code AS concept_code,
ROUND(denominator_value, (3 - FLOOR(LOG(denominator_value)) - 1)::INT) AS value, -- round quant value
denominator_unit AS unit
FROM ds_stage
WHERE COALESCE(denominator_value, 0) <> 0
AND COALESCE(numerator_value, 0) <> 0;
CREATE INDEX idx_q_quant ON q_quant (concept_code);
ANALYZE q_quant;
-- Create table with Dose Form information for each drug (if exists)
DROP TABLE IF EXISTS q_df;
CREATE UNLOGGED TABLE q_df AS
SELECT DISTINCT irs.concept_code_1 AS concept_code,
dcs.concept_code AS df_code -- distinct only because source may contain duplicated maps
FROM internal_relationship_stage irs
JOIN drug_concept_stage dcs ON dcs.concept_code = irs.concept_code_2
AND dcs.concept_class_id = 'Dose Form'
AND dcs.domain_id = 'Drug'; -- Dose Form of a drug
CREATE INDEX idx_q_df ON q_df (concept_code);
ANALYZE q_df;
-- Create table with Brand Name information for each drug including packs (if exists)
DROP TABLE IF EXISTS q_bn;
CREATE UNLOGGED TABLE q_bn AS
SELECT DISTINCT irs.concept_code_1 AS concept_code,
dcs.concept_code AS bn_code -- distinct only because source contains duplicated maps
FROM internal_relationship_stage irs
JOIN drug_concept_stage dcs ON dcs.concept_code = irs.concept_code_2
AND dcs.concept_class_id = 'Brand Name'
AND dcs.domain_id = 'Drug';-- Brand Name of a drug
CREATE INDEX idx_q_bn ON q_bn (concept_code);
ANALYZE q_bn;
-- Create table with Suppliers (manufacturers) including packs
DROP TABLE IF EXISTS q_mf;
CREATE UNLOGGED TABLE q_mf AS
SELECT DISTINCT irs.concept_code_1 AS concept_code,
dcs.concept_code AS mf_code -- distinct only because source contains duplicated maps
FROM internal_relationship_stage irs
JOIN drug_concept_stage dcs ON dcs.concept_code = irs.concept_code_2
AND dcs.concept_class_id = 'Supplier'
AND dcs.domain_id = 'Drug';-- Supplier of a drug
CREATE INDEX idx_q_mf ON q_mf (concept_code);
ANALYZE q_mf;
-- Create table with Box Size information
DROP TABLE IF EXISTS q_bs;
CREATE UNLOGGED TABLE q_bs AS
SELECT DISTINCT drug_concept_code AS concept_code,
box_size AS bs
FROM ds_stage
WHERE box_size IS NOT NULL;
CREATE INDEX idx_q_bs ON q_bs (concept_code);
ANALYZE q_bs;
/**************************************************************************
* 4. Create the list of all all existing q products in attribute notation *
***************************************************************************/
-- Duplication rule 1: More than one definition per concept_code is illegal
-- Duplication rule 2: More than one concept_code per definition is allowed.
-- Collect all input drugs and create master matrix, including assignment of concept_classes
DROP TABLE IF EXISTS q_existing;
CREATE UNLOGGED TABLE q_existing AS
-- Marketed Product
SELECT c.concept_code, COALESCE(q3.value, 0) AS quant_value, COALESCE(q3.unit, ' ') AS quant_unit, c.i_combo, c.d_combo, q1.df_code, COALESCE(q4.bn_code, ' ') AS bn_code, COALESCE(q5.bs, 0) AS bs, q2.mf_code AS mf_code, 'Marketed Product' AS concept_class_id
FROM q_combo c
JOIN q_df q1 ON q1.concept_code = c.concept_code
JOIN q_mf q2 ON q2.concept_code = c.concept_code
LEFT JOIN q_quant q3 ON q3.concept_code = c.concept_code
LEFT JOIN q_bn q4 ON q4.concept_code = c.concept_code
LEFT JOIN q_bs q5 ON q5.concept_code = c.concept_code
WHERE c.d_combo <> ' '
UNION ALL
-- Quant Branded Box
SELECT c.concept_code, q1.value AS quant_value, q1.unit AS quant_unit, c.i_combo, c.d_combo, q2.df_code, q3.bn_code, q4.bs, ' ' AS mf_code, 'Quant Branded Box' AS concept_class_id
FROM q_combo c
JOIN q_quant q1 ON q1.concept_code = c.concept_code
JOIN q_df q2 ON q2.concept_code = c.concept_code
JOIN q_bn q3 ON q3.concept_code = c.concept_code
JOIN q_bs q4 ON q4.concept_code = c.concept_code
LEFT JOIN q_mf q5 ON q5.concept_code = c.concept_code
WHERE c.d_combo <> ' '
AND q5.mf_code IS NULL
UNION ALL
-- Quant Clinical Box
SELECT c.concept_code, q1.value AS quant_value, q1.unit AS quant_unit, c.i_combo, c.d_combo, q2.df_code, ' ' AS bn_code, q4.bs, ' ' AS mf_code, 'Quant Clinical Box' AS concept_class_id
FROM q_combo c
JOIN q_quant q1 ON q1.concept_code = c.concept_code
JOIN q_df q2 ON q2.concept_code = c.concept_code
LEFT JOIN q_bn q3 ON q3.concept_code = c.concept_code
JOIN q_bs q4 ON q4.concept_code = c.concept_code
LEFT JOIN q_mf q5 ON q5.concept_code = c.concept_code
WHERE c.d_combo <> ' '
AND q3.concept_code IS NULL
AND q5.mf_code IS NULL
UNION ALL
-- Branded Drug Box
SELECT c.concept_code, 0 AS quant_value, ' ' AS quant_unit, c.i_combo, c.d_combo, q2.df_code, q3.bn_code, q4.bs, ' ' AS mf_code, 'Branded Drug Box' AS concept_class_id
FROM q_combo c
LEFT JOIN q_quant q1 ON q1.concept_code = c.concept_code
JOIN q_df q2 ON q2.concept_code = c.concept_code
JOIN q_bn q3 ON q3.concept_code = c.concept_code
JOIN q_bs q4 ON q4.concept_code = c.concept_code
LEFT JOIN q_mf q5 ON q5.concept_code = c.concept_code
WHERE q1.concept_code IS NULL
AND c.d_combo <> ' '
AND q5.mf_code IS NULL
UNION ALL
-- Clinical Drug Box
SELECT c.concept_code, 0 AS quant_value, ' ' AS quant_unit, c.i_combo, c.d_combo, q2.df_code, ' ' AS bn_code, q4.bs, ' ' AS mf_code, 'Clinical Drug Box' AS concept_class_id
FROM q_combo c
LEFT JOIN q_quant q1 ON q1.concept_code = c.concept_code
JOIN q_df q2 ON q2.concept_code = c.concept_code
LEFT JOIN q_bn q3 ON q3.concept_code = c.concept_code
JOIN q_bs q4 ON q4.concept_code = c.concept_code
LEFT JOIN q_mf q5 ON q5.concept_code = c.concept_code
WHERE q1.concept_code IS NULL
AND c.d_combo <> ' '
AND q3.concept_code IS NULL
AND q5.mf_code IS NULL
UNION ALL
-- Quant Branded Drug
SELECT c.concept_code, q1.value AS quant_value, q1.unit AS quant_unit, c.i_combo, c.d_combo, q2.df_code, q3.bn_code, 0 AS bs, ' ' AS mf_code, 'Quant Branded Drug' AS concept_class_id
FROM q_combo c
JOIN q_quant q1 ON q1.concept_code = c.concept_code
JOIN q_df q2 ON q2.concept_code = c.concept_code
JOIN q_bn q3 ON q3.concept_code = c.concept_code
LEFT JOIN q_bs q4 ON q4.concept_code = c.concept_code
LEFT JOIN q_mf q5 ON q5.concept_code = c.concept_code
WHERE c.d_combo <> ' '
AND q4.concept_code IS NULL
AND q5.mf_code IS NULL
UNION ALL
-- Quant Clinical Drug
SELECT c.concept_code, q1.value AS quant_value, q1.unit AS quant_unit, c.i_combo, c.d_combo, q2.df_code, ' ' AS bn_code, 0 AS bs, ' ' AS mf_code, 'Quant Clinical Drug' AS concept_class_id
FROM q_combo c
JOIN q_quant q1 ON q1.concept_code = c.concept_code
JOIN q_df q2 ON q2.concept_code = c.concept_code
LEFT JOIN q_bn q3 ON q3.concept_code = c.concept_code
LEFT JOIN q_bs q4 ON q4.concept_code = c.concept_code
LEFT JOIN q_mf q5 ON q5.concept_code = c.concept_code
WHERE c.d_combo <> ' '
AND q3.concept_code IS NULL
AND q4.concept_code IS NULL
AND q5.mf_code IS NULL
UNION ALL
-- Branded Drug
SELECT c.concept_code, 0 AS quant_value, ' ' AS quant_unit, c.i_combo, c.d_combo, q2.df_code, q3.bn_code, 0 AS bs, ' ' AS mf_code, 'Branded Drug' AS concept_class_id
FROM q_combo c
LEFT JOIN q_quant q1 ON q1.concept_code = c.concept_code
JOIN q_df q2 ON q2.concept_code = c.concept_code
JOIN q_bn q3 ON q3.concept_code = c.concept_code
LEFT JOIN q_bs q4 ON q4.concept_code = c.concept_code
LEFT JOIN q_mf q5 ON q5.concept_code = c.concept_code
WHERE q1.concept_code IS NULL
AND c.d_combo <> ' '
AND q4.concept_code IS NULL
AND q5.mf_code IS NULL
UNION ALL
-- Clinical Drug
SELECT c.concept_code, 0 AS quant_value, ' ' AS quant_unit, c.i_combo, c.d_combo, q2.df_code, ' ' AS bn_code, 0 AS bs, ' ' AS mf_code, 'Clinical Drug' AS concept_class_id
FROM q_combo c
LEFT JOIN q_quant q1 ON q1.concept_code = c.concept_code
JOIN q_df q2 ON q2.concept_code = c.concept_code
LEFT JOIN q_bn q3 ON q3.concept_code = c.concept_code
LEFT JOIN q_bs q4 ON q4.concept_code = c.concept_code
LEFT JOIN q_mf q5 ON q5.concept_code = c.concept_code
WHERE q1.concept_code IS NULL
AND c.d_combo <> ' '
AND q3.concept_code IS NULL
AND q4.concept_code IS NULL
AND q5.mf_code IS NULL
UNION ALL
-- Branded Drug Form
SELECT c.concept_code, 0 AS quant_value, ' ' AS quant_unit, c.i_combo, c.d_combo, q2.df_code, q3.bn_code, 0 AS bs, ' ' AS mf_code, 'Branded Drug Form' AS concept_class_id
FROM q_combo c
LEFT JOIN q_quant q1 ON q1.concept_code = c.concept_code
JOIN q_df q2 ON q2.concept_code = c.concept_code
JOIN q_bn q3 ON q3.concept_code = c.concept_code
LEFT JOIN q_bs q4 ON q4.concept_code = c.concept_code
LEFT JOIN q_mf q5 ON q5.concept_code = c.concept_code
WHERE q1.concept_code IS NULL
AND c.d_combo = ' '
AND q4.concept_code IS NULL
AND q5.mf_code IS NULL
UNION ALL
-- Clinical Drug Form
SELECT c.concept_code, 0 AS quant_value, ' ' AS quant_unit, c.i_combo, c.d_combo, q2.df_code, ' ' AS bn_code, 0 AS bs, ' ' AS mf_code, 'Clinical Drug Form' AS concept_class_id
FROM q_combo c
LEFT JOIN q_quant q1 ON q1.concept_code = c.concept_code
JOIN q_df q2 ON q2.concept_code = c.concept_code
LEFT JOIN q_bn q3 ON q3.concept_code = c.concept_code
LEFT JOIN q_bs q4 ON q4.concept_code = c.concept_code
LEFT JOIN q_mf q5 ON q5.concept_code = c.concept_code
WHERE q1.concept_code IS NULL
AND c.d_combo = ' '
AND q3.concept_code IS NULL
AND q4.concept_code IS NULL
AND q5.mf_code IS NULL
UNION ALL
-- Branded Drug Component
SELECT c.concept_code, 0 AS quant_value, ' ' AS quant_unit, c.i_combo, c.d_combo, ' ' AS df_code, q3.bn_code, 0 AS bs, ' ' AS mf_code, 'Branded Drug Comp' AS concept_class_id
FROM q_combo c
LEFT JOIN q_quant q1 ON q1.concept_code = c.concept_code
LEFT JOIN q_df q2 ON q2.concept_code = c.concept_code
JOIN q_bn q3 ON q3.concept_code = c.concept_code
LEFT JOIN q_bs q4 ON q4.concept_code = c.concept_code
LEFT JOIN q_mf q5 ON q5.concept_code = c.concept_code
WHERE q1.concept_code IS NULL
AND c.d_combo <> ' '
AND q2.concept_code IS NULL
AND q4.concept_code IS NULL
AND q5.mf_code IS NULL -- denominator_value is ignored
UNION ALL
-- Clinical Drug Component
SELECT c.concept_code, 0 AS quant_value, ' ' AS quant_unit, c.i_combo, c.d_combo, ' ' AS df_code, ' ' AS bn_code, 0 AS bs, ' ' AS mf_code, 'Clinical Drug Comp' AS concept_class_id
FROM q_combo c
LEFT JOIN q_quant q1 ON q1.concept_code = c.concept_code
LEFT JOIN q_df q2 ON q2.concept_code = c.concept_code
LEFT JOIN q_bn q3 ON q3.concept_code = c.concept_code
LEFT JOIN q_bs q4 ON q4.concept_code = c.concept_code
LEFT JOIN q_mf q5 ON q5.concept_code = c.concept_code
WHERE q1.concept_code IS NULL
AND c.d_combo <> ' '
AND q2.concept_code IS NULL
AND q3.concept_code IS NULL
AND q4.concept_code IS NULL
AND q5.mf_code IS NULL;
/******************************
* 4. Collect atributes for r *
******************************/
-- Create xxx-type codes for r ingredients, so we can add them
DROP TABLE IF EXISTS ing_stage;
CREATE UNLOGGED TABLE ing_stage AS
SELECT 'XXX' || NEXTVAL('xxx_seq') AS i_code,
concept_id AS i_id
FROM (
SELECT *
FROM concept
WHERE vocabulary_id IN (
'RxNorm',
'RxNorm Extension'
)
AND concept_class_id = 'Ingredient'
ORDER BY concept_id --just for sequence repeatability
) AS s0;
CREATE INDEX idx_ing_stage ON ing_stage (i_id);
ANALYZE ing_stage;
-- Create table with all drug concepts linked to the codes of the ingredients (rather than full dose components)
DROP TABLE IF EXISTS r_ing;
CREATE UNLOGGED TABLE r_ing AS
SELECT *
FROM (
SELECT de.concept_id AS concept_id,
an.concept_id AS i_id
FROM concept_ancestor a
JOIN concept an ON a.ancestor_concept_id = an.concept_id
AND an.vocabulary_id IN (
'RxNorm',
'RxNorm Extension'
)
AND an.concept_class_id = 'Ingredient'
JOIN concept de ON de.concept_id = a.descendant_concept_id
AND de.vocabulary_id IN (
'RxNorm',
'RxNorm Extension'
)
AND de.concept_class_id IN (
'Clinical Drug Form',
'Branded Drug Form'
)
UNION
SELECT ds.drug_concept_id AS concept_id,
ds.ingredient_concept_id AS i_id
FROM drug_strength ds -- just in case, won't hurt if the internal_relationship table forgot something
JOIN concept c ON c.concept_id = ds.drug_concept_id
AND c.vocabulary_id IN (
'RxNorm',
'RxNorm Extension'
)
WHERE ds.drug_concept_id <> ds.ingredient_concept_id -- in future, ingredients will also have records, where drug and ingredient ids are the same
) AS s0
JOIN ing_stage USING (i_id);
-- Create table with unique dosages
DROP TABLE IF EXISTS r_uds;
CREATE UNLOGGED TABLE r_uds AS
SELECT NEXTVAL('ds_seq')::VARCHAR AS ds_code,
ds.*
FROM (
SELECT *
FROM (
-- reuse the same sequence for q_ds and r_ds
SELECT DISTINCT i.i_code, -- use internal codes instead of concept id, so new ones can be added later.
ds.ingredient_concept_id, -- still keep it for faster creation of r_ds, but don't use it otherwise
COALESCE(ds.amount_value, 0) AS amount_value,
COALESCE(ds.amount_unit_concept_id, 0) AS amount_unit_concept_id,
COALESCE(ds.numerator_value, 0) AS numerator_value,
COALESCE(ds.numerator_unit_concept_id, 0) AS numerator_unit_concept_id,
CASE -- % and homeopathics should have an undefined denominator_unit. r_quant will eventually get it from ds_stage.
WHEN ds.numerator_unit_concept_id IN (
8554,
9325,
9324
)
THEN NULL
ELSE COALESCE(ds.denominator_unit_concept_id, 0)
END AS denominator_unit_concept_id
FROM drug_strength ds
JOIN ing_stage i ON i.i_id = ds.ingredient_concept_id
JOIN concept c ON c.concept_id = ds.drug_concept_id
AND c.vocabulary_id IN (
'RxNorm',
'RxNorm Extension'
)
AND c.concept_class_id NOT IN (
'Ingredient',
'Clinical Drug Form',
'Branded Drug Form'
) -- exclude these, since they are now part of drug_strength, but don't have strength information
WHERE ds.denominator_value IS NULL -- don't use Quant Drugs, because their numerator value is rounded in drug_strength. Use the non-quantified version instead
) s0
ORDER BY s0.i_code, --just for sequence repeatability
s0.ingredient_concept_id,
s0.amount_value,
s0.amount_unit_concept_id,
s0.numerator_value,
s0.numerator_unit_concept_id,
s0.denominator_unit_concept_id
) ds;
-- Create table with all drug concept codes linked to the above unique components
DROP TABLE IF EXISTS r_ds;
CREATE UNLOGGED TABLE r_ds AS
WITH w_uds AS (
SELECT ds.drug_concept_id,
ds.ingredient_concept_id,
i.i_code,
COALESCE(ds.amount_value, 0) AS amount_value,
COALESCE(ds.amount_unit_concept_id, 0) AS amount_unit_concept_id,
COALESCE(ds.numerator_value, 0) AS numerator_value,
COALESCE(ds.numerator_unit_concept_id, 0) AS numerator_unit_concept_id,
CASE -- % and homeopathics should have an undefined denominator_unit. r_quant will get it eventually from ds_stage
WHEN ds.numerator_unit_concept_id IN (
8554,
9325,
9324
)
THEN NULL
ELSE COALESCE(ds.denominator_unit_concept_id, 0)
END AS denominator_unit_concept_id
FROM drug_strength ds
JOIN ing_stage i ON i.i_id = ds.ingredient_concept_id
WHERE ds.denominator_value IS NULL -- don't use Quant Drugs, because their numerator value is rounded in drug_strength. Use the non-quantified version instead
)
SELECT DISTINCT ds.drug_concept_id AS concept_id, uds.i_code, uds.ds_code, uds.denominator_unit_concept_id AS quant_unit_id
FROM (
SELECT u.drug_concept_id, u.ingredient_concept_id, u.amount_value, u.amount_unit_concept_id, u.numerator_value, u.numerator_unit_concept_id, u.denominator_unit_concept_id
FROM w_uds u
JOIN concept c ON c.concept_id = u.drug_concept_id
AND c.vocabulary_id IN (
'RxNorm',
'RxNorm Extension'
)
AND c.concept_class_id NOT IN (
'Ingredient',
'Clinical Drug Form',
'Branded Drug Form'
) -- exclude these, since they are now part of drug_strength, but don't have strength information
UNION ALL -- get the drug strength information for the quantified versions of a drug from the non-quantified
SELECT cr.concept_id_2, u.ingredient_concept_id, u.amount_value, u.amount_unit_concept_id, u.numerator_value, u.numerator_unit_concept_id, u.denominator_unit_concept_id
FROM w_uds u
JOIN concept c1 ON c1.concept_id = u.drug_concept_id
AND c1.vocabulary_id IN (
'RxNorm',
'RxNorm Extension'
)
AND c1.invalid_reason IS NULL
JOIN concept_relationship cr ON cr.concept_id_1 = c1.concept_id
AND cr.invalid_reason IS NULL
AND cr.relationship_id = 'Has quantified form'
JOIN concept c2 ON c2.concept_id = cr.concept_id_2
AND c2.invalid_reason IS NULL -- check that resulting quantified is valid
UNION ALL -- get the drug strength information for Marketed Products from the non-quantified version of the non-marketed quant drug
SELECT cr2.concept_id_2, u.ingredient_concept_id, u.amount_value, u.amount_unit_concept_id, u.numerator_value, u.numerator_unit_concept_id, u.denominator_unit_concept_id
FROM w_uds u
JOIN concept c1 ON c1.concept_id = u.drug_concept_id
AND c1.vocabulary_id IN (
'RxNorm',
'RxNorm Extension'
)
AND c1.invalid_reason IS NULL
JOIN concept_relationship cr1 ON cr1.concept_id_1 = c1.concept_id
AND cr1.invalid_reason IS NULL
AND cr1.relationship_id = 'Has quantified form'
JOIN concept c2 ON c2.concept_id = cr1.concept_id_2
AND c2.invalid_reason IS NULL -- check that resulting quantified is valid
JOIN concept_relationship cr2 ON cr2.concept_id_1 = cr1.concept_id_2
AND cr2.invalid_reason IS NULL
AND cr2.relationship_id = 'Has marketed form'
JOIN concept f ON f.concept_id = cr2.concept_id_2
AND f.invalid_reason IS NULL -- check that resulting marketed is valid
) ds
JOIN r_uds uds USING (ingredient_concept_id, amount_value, amount_unit_concept_id, numerator_value, numerator_unit_concept_id)
WHERE COALESCE(ds.denominator_unit_concept_id, -1) = COALESCE(uds.denominator_unit_concept_id, -1);-- match nulls for % and homeopathics
--create index idx_r_ds_dscode on r_ds (ds_code);
--create index idx_r_ds_concode on r_ds (concept_id);
--analyze r_ds;
-- Create table with the combination of ds components for each drug concept delimited by '-'
-- Add corresponding ingredient combos
DROP TABLE IF EXISTS r_combo;
CREATE UNLOGGED TABLE r_combo AS
SELECT concept_id,
STRING_AGG(i_code, '-' ORDER BY i_code) AS i_combo,
STRING_AGG(ds_code, '-' ORDER BY LPAD(ds_code, 10, '0')) AS d_combo
FROM r_ds
GROUP BY concept_id
having count (i_code) = count(distinct i_code)
;
-- Add Drug Forms, which have no entry in ds_stage.
INSERT INTO r_combo
SELECT concept_id,
STRING_AGG(i_code, '-' ORDER BY i_code) AS i_combo,
' ' AS d_combo
FROM r_ing i
WHERE NOT EXISTS (
SELECT 1
FROM r_combo r
WHERE r.concept_id = i.concept_id
)
GROUP BY concept_id
having count (i_code) = count(distinct i_code);
CREATE INDEX idx_r_combo ON r_combo (concept_id);
ANALYZE r_combo;
-- Create table with Quantity Factor information for each drug (if exists), not rounded
DROP TABLE IF EXISTS r_quant;
CREATE UNLOGGED TABLE r_quant AS
SELECT DISTINCT drug_concept_id AS concept_id,
denominator_value AS value,
denominator_unit_concept_id AS unit_id
FROM drug_strength ds
JOIN concept c ON c.concept_id = ds.drug_concept_id
AND c.vocabulary_id IN (
'RxNorm',
'RxNorm Extension'
)
WHERE ds.denominator_value IS NOT NULL
AND ds.numerator_value IS NOT NULL
AND ds.drug_concept_id <> ds.ingredient_concept_id;
CREATE INDEX idx_r_quant ON r_quant (concept_id);
ANALYZE r_quant;
-- Create table with Dose Form information for each drug (if exists)
DROP TABLE IF EXISTS r_df;
CREATE UNLOGGED TABLE r_df AS
SELECT cr.concept_id_1 AS concept_id,
cr.concept_id_2 AS df_id
FROM concept_relationship cr
JOIN concept c1 ON c1.concept_id = cr.concept_id_1
AND c1.vocabulary_id IN (
'RxNorm',
'RxNorm Extension'
)
AND c1.standard_concept = 'S'
JOIN concept c2 ON c2.concept_id = cr.concept_id_2
AND c2.concept_class_id = 'Dose Form'
AND c2.invalid_reason IS NULL
WHERE cr.invalid_reason IS NULL
AND cr.relationship_id = 'RxNorm has dose form';
CREATE INDEX idx_r_df ON r_df (concept_id);
ANALYZE r_df;
-- Create table with Brand Name information for each drug (if exists)
DROP TABLE IF EXISTS r_bn;
CREATE UNLOGGED TABLE r_bn AS
SELECT cr.concept_id_1 AS concept_id,
cr.concept_id_2 AS bn_id
FROM concept_relationship cr
JOIN concept c1 ON c1.concept_id = cr.concept_id_1
AND c1.vocabulary_id IN (
'RxNorm',
'RxNorm Extension'
)
AND c1.standard_concept = 'S'
JOIN concept c2 ON c2.concept_id = cr.concept_id_2
AND c2.concept_class_id = 'Brand Name'
AND c2.invalid_reason IS NULL
WHERE cr.invalid_reason IS NULL
AND cr.relationship_id = 'Has brand name';
CREATE INDEX idx_r_bn ON r_bn (concept_id);
ANALYZE r_bn;
-- Create table with Suppliers (manufacturers)
DROP TABLE IF EXISTS r_mf;
CREATE UNLOGGED TABLE r_mf AS
SELECT cr.concept_id_1 AS concept_id,
cr.concept_id_2 AS mf_id
FROM concept_relationship cr
JOIN concept c1 ON c1.concept_id = cr.concept_id_1
AND c1.vocabulary_id IN (
'RxNorm',
'RxNorm Extension'
)
AND c1.standard_concept = 'S'
JOIN concept c2 ON c2.concept_id = cr.concept_id_2
AND c2.concept_class_id = 'Supplier'
AND c2.invalid_reason IS NULL
WHERE cr.invalid_reason IS NULL
AND cr.relationship_id = 'Has supplier';
CREATE INDEX idx_r_mf ON r_mf (concept_id);
ANALYZE r_mf;
-- Create table with Box Size information
DROP TABLE IF EXISTS r_bs;
CREATE UNLOGGED TABLE r_bs AS
SELECT DISTINCT drug_concept_id AS concept_id,
box_size AS bs
FROM drug_strength
JOIN concept d ON d.concept_id = drug_concept_id
AND d.vocabulary_id IN (
'RxNorm',
'RxNorm Extension'
) -- XXXX remove aftr DPD is gone
WHERE box_size IS NOT NULL;
CREATE INDEX idx_r_bs ON r_bs (concept_id);
ANALYZE r_bs;
/**************************************************************************
* 5. Create the list of all all existing r products in attribute notation *
***************************************************************************/
-- Create a blacklist of concepts with attribute problems that break conventions
drop table if exists workaround_cleanup
;
create unlogged table workaround_cleanup as
--Remove drugs that have more than one component with the same ingredient
with cd_to_comp as
(
select
c.concept_id as problematic_concept_id
from concept c
join concept_relationship r on
r.concept_id_1 = c.concept_id and
c.standard_concept = 'S' and
c.vocabulary_id in ('RxNorm', 'RxNorm Extension') and
r.relationship_id = 'Consists of' and
r.invalid_reason is NULL
join concept c2 on
c2.concept_id = r.concept_id_2 and
c2.concept_class_id in ('Clinical Drug Comp', 'Branded Drug Comp')
join drug_strength d on
d.drug_concept_id = c2.concept_id
group by c.concept_id
having count (ingredient_concept_id) > count (distinct ingredient_concept_id)
),
exclusion as
(
select a.descendant_concept_id
from concept_ancestor a
join cd_to_comp b on
problematic_concept_id = ancestor_concept_id
)
select concept_id, 'Components of same ingredient present'
from concept
join exclusion on
concept_id = descendant_concept_id
union all
--This will remove concepts that have valid relation to inactive attributes; Build_RxE would otherwise treat them as duplicate concepts of another class
select concept_id as bad_concept_id, 'Valid relation to invalid attribute' as exclusion_criterion
from concept c
where
c.invalid_reason is null and
c.vocabulary_id in ('RxNorm', 'RxNorm Extension') and
c.domain_id = 'Drug' and
c.concept_class_id != 'Ingredient' and
c.concept_id in
(
select concept_id_2
from concept_relationship r
join concept c on
r.relationship_id = 'Brand name of' and
c.concept_id = r.concept_id_1 and
c.concept_class_id = 'Brand Name' and
c.vocabulary_id in ('RxNorm', 'RxNorm Extension') and
c.invalid_reason is not null and
r.invalid_reason is null
--some may still have another valid attribute