Shared Entity References
This module references the following shared entities defined in their owning modules. PIS does not redefine these tables — it uses foreign-key references only.
| Shared Entity |
Owning Module |
Table(s) |
FK Used Here |
| Patients |
ehr-patient-mgmt |
patients, patient_demographics, patient_identifiers |
patients.patient_id |
| Providers |
ehr-patient-mgmt |
providers, provider_credentials |
providers.provider_id |
| Encounters |
scheduling |
encounters, encounter_details |
encounters.encounter_id |
| Users & Auth |
ehr-patient-mgmt |
users, roles, permissions |
users.user_id |
| Facilities |
ehr-patient-mgmt |
facilities, departments, locations |
facilities.facility_id, departments.department_id, locations.location_id |
| Payers |
policy-contract-mgmt |
payers, insurance_plans, contracts |
payers.payer_id |
| Patient Allergies |
ehr-patient-mgmt |
patient_allergies |
patient_allergies.allergy_id |
Entity Relationship Diagram
erDiagram
patients ||--o{ pharmacy_orders : "has"
encounters ||--o{ pharmacy_orders : "context for"
providers ||--o{ pharmacy_orders : "ordered by"
facilities ||--o{ pharmacy_orders : "at"
users ||--o{ pharmacy_orders : "verified by"
pharmacy_orders ||--o{ pharmacy_dispensing : "fulfilled by"
pharmacy_orders ||--o{ medication_administration : "administered as"
pharmacy_orders ||--o{ iv_admixture_orders : "has admixture"
pharmacy_orders ||--o{ pharmacy_interventions : "has"
pharmacy_orders ||--o{ antimicrobial_stewardship_reviews : "reviewed in"
pharmacy_orders ||--o{ medication_reconciliation : "referenced by"
formulary ||--o{ formulary_items : "contains"
formulary_items ||--o{ pharmacy_orders : "constrains"
formulary_items ||--o{ pharmacy_inventory : "stocks"
formulary_items ||--o{ iv_admixture_orders : "uses"
pharmacy_inventory ||--o{ inventory_transactions : "tracked by"
pharmacy_inventory ||--o{ controlled_substance_log : "controlled in"
patients ||--o{ medication_administration : "receives"
encounters ||--o{ medication_administration : "during"
users ||--o{ medication_administration : "administered by"
patients ||--o{ medication_reconciliation : "has"
encounters ||--o{ medication_reconciliation : "at transition"
pharmacy_orders {
bigint order_id PK
bigint patient_id FK
bigint encounter_id FK
bigint ordering_provider_id FK
bigint facility_id FK
bigint verified_by FK
}
pharmacy_dispensing {
bigint dispensing_id PK
bigint order_id FK
bigint patient_id FK
bigint dispensed_by FK
bigint verified_by FK
bigint dispensing_location_id FK
}
medication_administration {
bigint admin_id PK
bigint order_id FK
bigint patient_id FK
bigint encounter_id FK
bigint administered_by FK
bigint witness_id FK
}
formulary {
bigint formulary_id PK
bigint facility_id FK
bigint approved_by FK
}
formulary_items {
bigint item_id PK
bigint formulary_id FK
}
drug_interactions {
bigint interaction_id PK
}
pharmacy_inventory {
bigint inventory_id PK
bigint facility_id FK
bigint location_id FK
}
inventory_transactions {
bigint transaction_id PK
bigint inventory_id FK
bigint from_location_id FK
bigint to_location_id FK
bigint performed_by FK
}
controlled_substance_log {
bigint log_id PK
bigint from_user_id FK
bigint to_user_id FK
bigint witness_id FK
bigint patient_id FK
bigint waste_witnessed_by FK
bigint location_id FK
}
iv_admixture_orders {
bigint admixture_id PK
bigint order_id FK
bigint prepared_by FK
bigint verified_by FK
}
pharmacy_interventions {
bigint intervention_id PK
bigint order_id FK
bigint pharmacist_id FK
}
medication_reconciliation {
bigint recon_id PK
bigint patient_id FK
bigint encounter_id FK
bigint new_order_id FK
bigint reconciled_by FK
}
antimicrobial_stewardship_reviews {
bigint review_id PK
bigint order_id FK
bigint patient_id FK
bigint reviewed_by FK
}
Table Definitions
Conventions:
- All timestamps are in TIMESTAMP WITH TIME ZONE unless noted.
- All PKs use GENERATED ALWAYS AS IDENTITY.
- DB syntax is PostgreSQL-compatible.
- UAE-specific: controlled substance fields aligned with UAE MOH schedules; no US-specific schedules.
1. pharmacy_orders
Purpose
Stores all medication orders as received and managed by the Pharmacy Information System, including inpatient, outpatient, and discharge prescriptions. Supports clinical decision support, formulary checks, and UAE MOH controlled substance compliance.
Field Specifications
| Field |
Type |
Nullable |
Default |
Constraint |
Description |
order_id |
BIGINT |
NO |
IDENTITY |
PK |
Internal pharmacy order identifier |
external_order_id |
VARCHAR(50) |
YES |
NULL |
Unique per source |
ID from CPOE/LIS if applicable |
order_source_system |
VARCHAR(30) |
NO |
'CPOE' |
IN ('CPOE','OPD','ED','Manual') |
Source of order |
patient_id |
BIGINT |
NO |
— |
FK → patients.patient_id |
Patient receiving medication |
encounter_id |
BIGINT |
YES |
NULL |
FK → encounters.encounter_id |
Encounter context (nullable for pure outpatient retail) |
ordering_provider_id |
BIGINT |
NO |
— |
FK → providers.provider_id |
Prescribing clinician |
facility_id |
BIGINT |
NO |
— |
FK → facilities.facility_id |
Ordering facility |
department_id |
BIGINT |
YES |
NULL |
FK → departments.department_id |
Ordering department/ward |
order_type |
VARCHAR(20) |
NO |
'inpatient' |
IN ('inpatient','outpatient','discharge') |
Context of order |
order_status |
VARCHAR(20) |
NO |
'pending_verification' |
IN ('pending_verification','verified','rejected','on_hold','discontinued','completed','cancelled') |
Pharmacy order status |
priority |
VARCHAR(10) |
NO |
'routine' |
IN ('stat','urgent','first_dose','routine') |
Priority for verification/dispensing |
drug_code_rxnorm |
VARCHAR(20) |
NO |
— |
RxNorm code |
Ordered drug code |
drug_name |
VARCHAR(255) |
NO |
— |
— |
Display name (usually generic + strength + form) |
dose |
NUMERIC(12,3) |
NO |
— |
> 0 |
Dose amount per administration |
dose_unit |
VARCHAR(20) |
NO |
— |
UCUM code |
Dose unit (e.g., mg, mL) |
route |
VARCHAR(30) |
NO |
— |
From Administration Routes MD |
Route of administration |
frequency |
VARCHAR(30) |
NO |
— |
From Medication Frequencies MD |
Frequency code (e.g., BID, Q8H) |
duration_days |
INT |
YES |
NULL |
> 0 if not null |
Planned duration in days |
prn_flag |
BOOLEAN |
NO |
FALSE |
— |
As-needed medication flag |
prn_indication |
VARCHAR(255) |
YES |
NULL |
Required if prn_flag = TRUE |
Reason for PRN use |
indication_icd10 |
VARCHAR(10) |
YES |
NULL |
ICD-10-AM format |
Diagnosis code for indication |
indication_text |
VARCHAR(500) |
YES |
NULL |
— |
Free-text indication |
weight_kg_at_order |
NUMERIC(6,2) |
YES |
NULL |
≥ 0 |
Patient weight used for dosing |
bsa_m2_at_order |
NUMERIC(5,3) |
YES |
NULL |
≥ 0 |
Body surface area if used |
renal_function_json |
JSONB |
YES |
NULL |
— |
Snapshot of creatinine clearance/eGFR used for dosing |
order_datetime |
TIMESTAMP WITH TIME ZONE |
NO |
CURRENT_TIMESTAMP |
— |
When order was received in PIS |
verified_by |
BIGINT |
YES |
NULL |
FK → users.user_id |
Pharmacist who verified |
verified_datetime |
TIMESTAMP WITH TIME ZONE |
YES |
NULL |
≥ order_datetime |
When verification completed |
verification_outcome |
VARCHAR(20) |
YES |
NULL |
IN ('approved','modified','rejected') |
Outcome of verification |
verification_notes |
TEXT |
YES |
NULL |
— |
Rationale for modifications/rejections |
formulary_item_id |
BIGINT |
YES |
NULL |
FK → formulary_items.item_id |
Linked formulary item if applicable |
non_formulary_reason |
VARCHAR(255) |
YES |
NULL |
— |
Reason for non-formulary use |
insurance_payer_id |
BIGINT |
YES |
NULL |
FK → payers.payer_id |
Payer at time of order |
prior_auth_required |
BOOLEAN |
NO |
FALSE |
— |
From formulary/plan rules |
prior_auth_status |
VARCHAR(20) |
YES |
NULL |
IN ('not_required','pending','approved','denied') |
PA status |
is_controlled |
BOOLEAN |
NO |
FALSE |
— |
UAE MOH controlled substance flag |
controlled_schedule |
VARCHAR(20) |
YES |
NULL |
UAE MOH schedule (e.g., 'CDa-Narcotic','CDa-Psychotropic','CDb') |
UAE controlled classification |
uep_required |
BOOLEAN |
NO |
FALSE |
— |
Requires MOH electronic prescription (UEP) |
uep_prescription_id |
VARCHAR(50) |
YES |
NULL |
— |
ID returned by MOH UEP system |
max_daily_dose |
NUMERIC(12,3) |
YES |
NULL |
≥ 0 |
Calculated max daily dose for safety |
cds_alerts_json |
JSONB |
YES |
NULL |
— |
Snapshot of CDS alerts at verification |
override_flags_json |
JSONB |
YES |
NULL |
— |
Documented overrides (allergy, interaction, etc.) |
created_by |
BIGINT |
NO |
— |
FK → users.user_id |
User who created record |
updated_by |
BIGINT |
YES |
NULL |
FK → users.user_id |
Last user to update |
created_at |
TIMESTAMP WITH TIME ZONE |
NO |
CURRENT_TIMESTAMP |
— |
Creation timestamp |
updated_at |
TIMESTAMP WITH TIME ZONE |
NO |
CURRENT_TIMESTAMP |
ON UPDATE |
Last update timestamp |
SQL DDL
SQLCREATE TABLE pharmacy_orders (
order_id BIGINT GENERATED ALWAYS AS IDENTITY PRIMARY KEY,
external_order_id VARCHAR(50),
order_source_system VARCHAR(30) NOT NULL DEFAULT 'CPOE',
patient_id BIGINT NOT NULL,
encounter_id BIGINT,
ordering_provider_id BIGINT NOT NULL,
facility_id BIGINT NOT NULL,
department_id BIGINT,
order_type VARCHAR(20) NOT NULL DEFAULT 'inpatient',
order_status VARCHAR(20) NOT NULL DEFAULT 'pending_verification',
priority VARCHAR(10) NOT NULL DEFAULT 'routine',
drug_code_rxnorm VARCHAR(20) NOT NULL,
drug_name VARCHAR(255) NOT NULL,
dose NUMERIC(12,3) NOT NULL,
dose_unit VARCHAR(20) NOT NULL,
route VARCHAR(30) NOT NULL,
frequency VARCHAR(30) NOT NULL,
duration_days INT,
prn_flag BOOLEAN NOT NULL DEFAULT FALSE,
prn_indication VARCHAR(255),
indication_icd10 VARCHAR(10),
indication_text VARCHAR(500),
weight_kg_at_order NUMERIC(6,2),
bsa_m2_at_order NUMERIC(5,3),
renal_function_json JSONB,
order_datetime TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT CURRENT_TIMESTAMP,
verified_by BIGINT,
verified_datetime TIMESTAMP WITH TIME ZONE,
verification_outcome VARCHAR(20),
verification_notes TEXT,
formulary_item_id BIGINT,
non_formulary_reason VARCHAR(255),
insurance_payer_id BIGINT,
prior_auth_required BOOLEAN NOT NULL DEFAULT FALSE,
prior_auth_status VARCHAR(20),
is_controlled BOOLEAN NOT NULL DEFAULT FALSE,
controlled_schedule VARCHAR(20),
uep_required BOOLEAN NOT NULL DEFAULT FALSE,
uep_prescription_id VARCHAR(50),
max_daily_dose NUMERIC(12,3),
cds_alerts_json JSONB,
override_flags_json JSONB,
created_by BIGINT NOT NULL,
updated_by BIGINT,
created_at TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT CURRENT_TIMESTAMP,
updated_at TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT CURRENT_TIMESTAMP
);
ALTER TABLE pharmacy_orders
ADD CONSTRAINT fk_pharm_orders_patient
FOREIGN KEY (patient_id) REFERENCES patients(patient_id) ON UPDATE CASCADE ON DELETE RESTRICT,
ADD CONSTRAINT fk_pharm_orders_encounter
FOREIGN KEY (encounter_id) REFERENCES encounters(encounter_id) ON UPDATE CASCADE ON DELETE SET NULL,
ADD CONSTRAINT fk_pharm_orders_provider
FOREIGN KEY (ordering_provider_id) REFERENCES providers(provider_id) ON UPDATE CASCADE ON DELETE RESTRICT,
ADD CONSTRAINT fk_pharm_orders_facility
FOREIGN KEY (facility_id) REFERENCES facilities(facility_id) ON UPDATE CASCADE ON DELETE RESTRICT,
ADD CONSTRAINT fk_pharm_orders_department
FOREIGN KEY (department_id) REFERENCES departments(department_id) ON UPDATE CASCADE ON DELETE SET NULL,
ADD CONSTRAINT fk_pharm_orders_formulary_item
FOREIGN KEY (formulary_item_id) REFERENCES formulary_items(item_id) ON UPDATE CASCADE ON DELETE SET NULL,
ADD CONSTRAINT fk_pharm_orders_payer
FOREIGN KEY (insurance_payer_id) REFERENCES payers(payer_id) ON UPDATE CASCADE ON DELETE SET NULL,
ADD CONSTRAINT fk_pharm_orders_verified_by
FOREIGN KEY (verified_by) REFERENCES users(user_id) ON UPDATE CASCADE ON DELETE SET NULL,
ADD CONSTRAINT fk_pharm_orders_created_by
FOREIGN KEY (created_by) REFERENCES users(user_id) ON UPDATE CASCADE ON DELETE RESTRICT,
ADD CONSTRAINT fk_pharm_orders_updated_by
FOREIGN KEY (updated_by) REFERENCES users(user_id) ON UPDATE CASCADE ON DELETE SET NULL,
ADD CONSTRAINT chk_pharm_orders_order_type
CHECK (order_type IN ('inpatient','outpatient','discharge')),
ADD CONSTRAINT chk_pharm_orders_status
CHECK (order_status IN ('pending_verification','verified','rejected','on_hold','discontinued','completed','cancelled')),
ADD CONSTRAINT chk_pharm_orders_priority
CHECK (priority IN ('stat','urgent','first_dose','routine')),
ADD CONSTRAINT chk_pharm_orders_dose_positive
CHECK (dose > 0),
ADD CONSTRAINT chk_pharm_orders_duration_positive
CHECK (duration_days IS NULL OR duration_days > 0),
ADD CONSTRAINT chk_pharm_orders_prn_indication
CHECK (prn_flag = FALSE OR prn_indication IS NOT NULL),
ADD CONSTRAINT chk_pharm_orders_verification_outcome
CHECK (verification_outcome IS NULL OR verification_outcome IN ('approved','modified','rejected')),
ADD CONSTRAINT chk_pharm_orders_prior_auth_status
CHECK (prior_auth_status IS NULL OR prior_auth_status IN ('not_required','pending','approved','denied')),
ADD CONSTRAINT chk_pharm_orders_controlled_schedule
CHECK (is_controlled = FALSE OR controlled_schedule IS NOT NULL);
CREATE INDEX idx_pharm_orders_patient ON pharmacy_orders(patient_id);
CREATE INDEX idx_pharm_orders_encounter ON pharmacy_orders(encounter_id);
CREATE INDEX idx_pharm_orders_status ON pharmacy_orders(order_status);
CREATE INDEX idx_pharm_orders_priority ON pharmacy_orders(priority);
CREATE INDEX idx_pharm_orders_verified_dt ON pharmacy_orders(verified_datetime);
CREATE INDEX idx_pharm_orders_drug ON pharmacy_orders(drug_code_rxnorm);
CREATE INDEX idx_pharm_orders_controlled ON pharmacy_orders(is_controlled) WHERE is_controlled = TRUE;
CREATE INDEX idx_pharm_orders_facility_status ON pharmacy_orders(facility_id, order_status);
Terminology Bindings
| Field |
Terminology |
Example Value |
drug_code_rxnorm |
RxNorm |
1049630 (paracetamol 500 mg tablet) |
dose_unit |
UCUM |
mg, mL, unit |
route |
SNOMED CT / HL7 Route Codes |
PO (oral), IV, IM |
frequency |
Facility Medication Frequencies MD |
BID, Q8H, PRN |
indication_icd10 |
ICD-10-AM |
E11.9 |
controlled_schedule |
UAE MOH Controlled Substance Schedules MD |
CDa-Narcotic |
FHIR Resource Mapping
| Table Field |
FHIR Resource |
FHIR Path |
order_id |
MedicationRequest |
MedicationRequest.id |
patient_id |
MedicationRequest |
MedicationRequest.subject.reference (Patient/{id}) |
encounter_id |
MedicationRequest |
MedicationRequest.encounter.reference |
ordering_provider_id |
MedicationRequest |
MedicationRequest.requester.reference (Practitioner/{id}) |
order_type |
MedicationRequest |
MedicationRequest.category (inpatient/outpatient) |
order_status |
MedicationRequest |
MedicationRequest.status |
priority |
MedicationRequest |
MedicationRequest.priority |
drug_code_rxnorm |
MedicationRequest |
MedicationRequest.medicationCodeableConcept.coding[RxNorm].code |
drug_name |
MedicationRequest |
MedicationRequest.medicationCodeableConcept.text |
dose, dose_unit |
MedicationRequest |
MedicationRequest.dosageInstruction.doseAndRate.doseQuantity |
route |
MedicationRequest |
MedicationRequest.dosageInstruction.route |
frequency, duration_days |
MedicationRequest |
MedicationRequest.dosageInstruction.timing |
prn_flag, prn_indication |
MedicationRequest |
MedicationRequest.dosageInstruction.asNeeded[x], .patientInstruction |
indication_icd10, indication_text |
MedicationRequest |
MedicationRequest.reasonCode |
order_datetime |
MedicationRequest |
MedicationRequest.authoredOn |
verified_by, verified_datetime |
MedicationRequest |
Extension: pharmacist verification details |
is_controlled, controlled_schedule, uep_prescription_id |
MedicationRequest |
UAE-specific extensions for controlled substances |
2. pharmacy_dispensing
Purpose
Captures each dispensing event (fill) associated with a pharmacy order, including inpatient unit-dose and outpatient prescription fills. Supports billing, inventory decrement, and HIE reporting (NABIDH/Malaffi).
Field Specifications
| Field |
Type |
Nullable |
Default |
Constraint |
Description |
dispensing_id |
BIGINT |
NO |
IDENTITY |
PK |
Unique dispensing event |
order_id |
BIGINT |
NO |
— |
FK → pharmacy_orders.order_id |
Related pharmacy order |
patient_id |
BIGINT |
NO |
— |
FK → patients.patient_id |
Patient |
encounter_id |
BIGINT |
YES |
NULL |
FK → encounters.encounter_id |
Encounter if applicable |
facility_id |
BIGINT |
NO |
— |
FK → facilities.facility_id |
Dispensing facility |
dispensing_location_id |
BIGINT |
YES |
NULL |
FK → locations.location_id |
Pharmacy/ADC location |
drug_code_rxnorm |
VARCHAR(20) |
NO |
— |
RxNorm |
Dispensed drug code |
ndc_code |
VARCHAR(20) |
YES |
NULL |
— |
Local pack code / GTIN if used |
quantity_dispensed |
NUMERIC(12,3) |
NO |
— |
> 0 |
Quantity dispensed |
quantity_unit |
VARCHAR(20) |
NO |
'unit' |
UCUM |
Unit for quantity (e.g., tablet, mL) |
days_supply |
INT |
YES |
NULL |
> 0 |
For outpatient fills |
lot_number |
VARCHAR(50) |
YES |
NULL |
— |
Batch/lot identifier |
expiry_date |
DATE |
YES |
NULL |
— |
Expiry of dispensed lot |
dispensed_by |
BIGINT |
NO |
— |
FK → users.user_id |
Technician/pharmacist who dispensed |
verified_by |
BIGINT |
YES |
NULL |
FK → users.user_id |
Pharmacist final check |
dispensing_datetime |
TIMESTAMP WITH TIME ZONE |
NO |
CURRENT_TIMESTAMP |
— |
When dispensed |
label_printed |
BOOLEAN |
NO |
FALSE |
— |
Label printed flag |
label_language |
VARCHAR(10) |
YES |
NULL |
IN ('en','ar','bilingual') |
Label language |
billing_status |
VARCHAR(20) |
NO |
'pending' |
IN ('pending','sent','accepted','rejected','not_billable') |
Billing integration status |
billing_reference |
VARCHAR(50) |
YES |
NULL |
— |
Reference to billing/DFT message |
is_controlled |
BOOLEAN |
NO |
FALSE |
— |
Copied from order/formulary |
controlled_log_id |
BIGINT |
YES |
NULL |
FK → controlled_substance_log.log_id |
Linked controlled log entry |
hie_submission_status |
VARCHAR(20) |
NO |
'pending' |
IN ('pending','accepted','rejected','error','not_required') |
NABIDH/Malaffi status |
hie_last_attempt |
TIMESTAMP WITH TIME ZONE |
YES |
NULL |
— |
Last HIE submission attempt |
hie_error_message |
TEXT |
YES |
NULL |
— |
Last HIE error details |
created_at |
TIMESTAMP WITH TIME ZONE |
NO |
CURRENT_TIMESTAMP |
— |
Creation timestamp |
updated_at |
TIMESTAMP WITH TIME ZONE |
NO |
CURRENT_TIMESTAMP |
ON UPDATE |
Last update timestamp |
SQL DDL
SQLCREATE TABLE pharmacy_dispensing (
dispensing_id BIGINT GENERATED ALWAYS AS IDENTITY PRIMARY KEY,
order_id BIGINT NOT NULL,
patient_id BIGINT NOT NULL,
encounter_id BIGINT,
facility_id BIGINT NOT NULL,
dispensing_location_id BIGINT,
drug_code_rxnorm VARCHAR(20) NOT NULL,
ndc_code VARCHAR(20),
quantity_dispensed NUMERIC(12,3) NOT NULL,
quantity_unit VARCHAR(20) NOT NULL DEFAULT 'unit',
days_supply INT,
lot_number VARCHAR(50),
expiry_date DATE,
dispensed_by BIGINT NOT NULL,
verified_by BIGINT,
dispensing_datetime TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT CURRENT_TIMESTAMP,
label_printed BOOLEAN NOT NULL DEFAULT FALSE,
label_language VARCHAR(10),
billing_status VARCHAR(20) NOT NULL DEFAULT 'pending',
billing_reference VARCHAR(50),
is_controlled BOOLEAN NOT NULL DEFAULT FALSE,
controlled_log_id BIGINT,
hie_submission_status VARCHAR(20) NOT NULL DEFAULT 'pending',
hie_last_attempt TIMESTAMP WITH TIME ZONE,
hie_error_message TEXT,
created_at TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT CURRENT_TIMESTAMP,
updated_at TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT CURRENT_TIMESTAMP
);
ALTER TABLE pharmacy_dispensing
ADD CONSTRAINT fk_disp_order
FOREIGN KEY (order_id) REFERENCES pharmacy_orders(order_id) ON UPDATE CASCADE ON DELETE RESTRICT,
ADD CONSTRAINT fk_disp_patient
FOREIGN KEY (patient_id) REFERENCES patients(patient_id) ON UPDATE CASCADE ON DELETE RESTRICT,
ADD CONSTRAINT fk_disp_encounter
FOREIGN KEY (encounter_id) REFERENCES encounters(encounter_id) ON UPDATE CASCADE ON DELETE SET NULL,
ADD CONSTRAINT fk_disp_facility
FOREIGN KEY (facility_id) REFERENCES facilities(facility_id) ON UPDATE CASCADE ON DELETE RESTRICT,
ADD CONSTRAINT fk_disp_location
FOREIGN KEY (dispensing_location_id) REFERENCES locations(location_id) ON UPDATE CASCADE ON DELETE SET NULL,
ADD CONSTRAINT fk_disp_dispensed_by
FOREIGN KEY (dispensed_by) REFERENCES users(user_id) ON UPDATE CASCADE ON DELETE RESTRICT,
ADD CONSTRAINT fk_disp_verified_by
FOREIGN KEY (verified_by) REFERENCES users(user_id) ON UPDATE CASCADE ON DELETE SET NULL,
ADD CONSTRAINT fk_disp_controlled_log
FOREIGN KEY (controlled_log_id) REFERENCES controlled_substance_log(log_id) ON UPDATE CASCADE ON DELETE SET NULL,
ADD CONSTRAINT chk_disp_quantity_positive
CHECK (quantity_dispensed > 0),
ADD CONSTRAINT chk_disp_days_supply
CHECK (days_supply IS NULL OR days_supply > 0),
ADD CONSTRAINT chk_disp_billing_status
CHECK (billing_status IN ('pending','sent','accepted','rejected','not_billable')),
ADD CONSTRAINT chk_disp_hie_status
CHECK (hie_submission_status IN ('pending','accepted','rejected','error','not_required')),
ADD CONSTRAINT chk_disp_label_language
CHECK (label_language IS NULL OR label_language IN ('en','ar','bilingual'));
CREATE INDEX idx_disp_order ON pharmacy_dispensing(order_id);
CREATE INDEX idx_disp_patient ON pharmacy_dispensing(patient_id);
CREATE INDEX idx_disp_datetime ON pharmacy_dispensing(dispensing_datetime);
CREATE INDEX idx_disp_billing_status ON pharmacy_dispensing(billing_status);
CREATE INDEX idx_disp_hie_status ON pharmacy_dispensing(hie_submission_status);
CREATE INDEX idx_disp_facility_datetime ON pharmacy_dispensing(facility_id, dispensing_datetime);
Terminology Bindings
| Field |
Terminology |
Example Value |
drug_code_rxnorm |
RxNorm |
1049630 |
quantity_unit |
UCUM / local |
tablet, mL |
FHIR Resource Mapping
| Table Field |
FHIR Resource |
FHIR Path |
dispensing_id |
MedicationDispense |
MedicationDispense.id |
order_id |
MedicationDispense |
MedicationDispense.authorizingPrescription.reference |
patient_id |
MedicationDispense |
MedicationDispense.subject.reference |
encounter_id |
MedicationDispense |
MedicationDispense.context.reference |
drug_code_rxnorm |
MedicationDispense |
MedicationDispense.medicationCodeableConcept.coding[RxNorm].code |
quantity_dispensed, quantity_unit |
MedicationDispense |
MedicationDispense.quantity |
days_supply |
MedicationDispense |
MedicationDispense.daysSupply |
dispensing_datetime |
MedicationDispense |
MedicationDispense.whenHandedOver |
dispensed_by |
MedicationDispense |
MedicationDispense.performer.actor |
lot_number, expiry_date |
MedicationDispense |
MedicationDispense.batch |
billing_status |
MedicationDispense |
Extension for billing status |
hie_submission_status |
MedicationDispense |
Extension for HIE submission tracking |
3. medication_administration
Purpose
Represents the electronic Medication Administration Record (eMAR) for inpatient and certain outpatient administrations, including barcode verification, PRN response, and refusal/hold reasons.
Field Specifications
| Field |
Type |
Nullable |
Default |
Constraint |
Description |
admin_id |
BIGINT |
NO |
IDENTITY |
PK |
Unique administration event |
order_id |
BIGINT |
NO |
— |
FK → pharmacy_orders.order_id |
Related order |
dispensing_id |
BIGINT |
YES |
NULL |
FK → pharmacy_dispensing.dispensing_id |
Source dispensing event |
patient_id |
BIGINT |
NO |
— |
FK → patients.patient_id |
Patient |
encounter_id |
BIGINT |
NO |
— |
FK → encounters.encounter_id |
Encounter |
facility_id |
BIGINT |
NO |
— |
FK → facilities.facility_id |
Facility |
location_id |
BIGINT |
YES |
NULL |
FK → locations.location_id |
Bed/ward at time of admin |
drug_code_rxnorm |
VARCHAR(20) |
NO |
— |
RxNorm |
Drug administered |
scheduled_datetime |
TIMESTAMP WITH TIME ZONE |
NO |
— |
— |
Scheduled time |
actual_datetime |
TIMESTAMP WITH TIME ZONE |
YES |
NULL |
— |
Actual administration time |
dose_given |
NUMERIC(12,3) |
YES |
NULL |
≥ 0 |
Dose actually given |
dose_unit |
VARCHAR(20) |
YES |
NULL |
UCUM |
Unit of dose given |
route |
VARCHAR(30) |
YES |
NULL |
— |
Route used |
site |
VARCHAR(50) |
YES |
NULL |
SNOMED CT body site if used |
Site for injections, etc. |
status |
VARCHAR(20) |
NO |
'scheduled' |
IN ('scheduled','in_progress','completed','held','refused','omitted','cancelled') |
Administration status |
hold_reason |
VARCHAR(255) |
YES |
NULL |
Required if status='held' |
Reason for hold |
refuse_reason |
VARCHAR(255) |
YES |
NULL |
Required if status='refused' |
Reason for refusal |
omission_reason |
VARCHAR(255) |
YES |
NULL |
Required if status='omitted' |
Reason for omission |
administered_by |
BIGINT |
YES |
NULL |
FK → users.user_id |
Nurse administering |
witness_id |
BIGINT |
YES |
NULL |
FK → users.user_id |
Witness for high-risk/controlled |
barcode_verified |
BOOLEAN |
NO |
FALSE |
— |
Barcode scan success |
patient_barcode |
VARCHAR(50) |
YES |
NULL |
— |
Scanned patient wristband value |
medication_barcode |
VARCHAR(50) |
YES |
NULL |
— |
Scanned medication barcode |
prn_indication |
VARCHAR(255) |
YES |
NULL |
— |
Reason for PRN dose |
prn_response |
TEXT |
YES |
NULL |
— |
Clinical response to PRN |
notes |
TEXT |
YES |
NULL |
— |
Additional nursing notes |
created_at |
TIMESTAMP WITH TIME ZONE |
NO |
CURRENT_TIMESTAMP |
— |
Creation timestamp |
updated_at |
TIMESTAMP WITH TIME ZONE |
NO |
CURRENT_TIMESTAMP |
ON UPDATE |
Last update timestamp |
SQL DDL
SQLCREATE TABLE medication_administration (
admin_id BIGINT GENERATED ALWAYS AS IDENTITY PRIMARY KEY,
order_id BIGINT NOT NULL,
dispensing_id BIGINT,
patient_id BIGINT NOT NULL,
encounter_id BIGINT NOT NULL,
facility_id BIGINT NOT NULL,
location_id BIGINT,
drug_code_rxnorm VARCHAR(20) NOT NULL,
scheduled_datetime TIMESTAMP WITH TIME ZONE NOT NULL,
actual_datetime TIMESTAMP WITH TIME ZONE,
dose_given NUMERIC(12,3),
dose_unit VARCHAR(20),
route VARCHAR(30),
site VARCHAR(50),
status VARCHAR(20) NOT NULL DEFAULT 'scheduled',
hold_reason VARCHAR(255),
refuse_reason VARCHAR(255),
omission_reason VARCHAR(255),
administered_by BIGINT,
witness_id BIGINT,
barcode_verified BOOLEAN NOT NULL DEFAULT FALSE,
patient_barcode VARCHAR(50),
medication_barcode VARCHAR(50),
prn_indication VARCHAR(255),
prn_response TEXT,
notes TEXT,
created_at TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT CURRENT_TIMESTAMP,
updated_at TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT CURRENT_TIMESTAMP
);
ALTER TABLE medication_administration
ADD CONSTRAINT fk_medadmin_order
FOREIGN KEY (order_id) REFERENCES pharmacy_orders(order_id) ON UPDATE CASCADE ON DELETE RESTRICT,
ADD CONSTRAINT fk_medadmin_dispensing
FOREIGN KEY (dispensing_id) REFERENCES pharmacy_dispensing(dispensing_id) ON UPDATE CASCADE ON DELETE SET NULL,
ADD CONSTRAINT fk_medadmin_patient
FOREIGN KEY (patient_id) REFERENCES patients(patient_id) ON UPDATE CASCADE ON DELETE RESTRICT,
ADD CONSTRAINT fk_medadmin_encounter
FOREIGN KEY (encounter_id) REFERENCES encounters(encounter_id) ON UPDATE CASCADE ON DELETE RESTRICT,
ADD CONSTRAINT fk_medadmin_facility
FOREIGN KEY (facility_id) REFERENCES facilities(facility_id) ON UPDATE CASCADE ON DELETE RESTRICT,
ADD CONSTRAINT fk_medadmin_location
FOREIGN KEY (location_id) REFERENCES locations(location_id) ON UPDATE CASCADE ON DELETE SET NULL,
ADD CONSTRAINT fk_medadmin_admin_by
FOREIGN KEY (administered_by) REFERENCES users(user_id) ON UPDATE CASCADE ON DELETE SET NULL,
ADD CONSTRAINT fk_medadmin_witness
FOREIGN KEY (witness_id) REFERENCES users(user_id) ON UPDATE CASCADE ON DELETE SET NULL,
ADD CONSTRAINT chk_medadmin_status
CHECK (status IN ('scheduled','in_progress','completed','held','refused','omitted','cancelled')),
ADD CONSTRAINT chk_medadmin_dose_nonnegative
CHECK (dose_given IS NULL OR dose_given >= 0),
ADD CONSTRAINT chk_medadmin_hold_reason
CHECK (status <> 'held' OR hold_reason IS NOT NULL),
ADD CONSTRAINT chk_medadmin_refuse_reason
CHECK (status <> 'refused' OR refuse_reason IS NOT NULL),
ADD CONSTRAINT chk_medadmin_omission_reason
CHECK (status <> 'omitted' OR omission_reason IS NOT NULL);
CREATE INDEX idx_medadmin_patient ON medication_administration(patient_id);
CREATE INDEX idx_medadmin_encounter ON medication_administration(encounter_id);
CREATE INDEX idx_medadmin_order ON medication_administration(order_id);
CREATE INDEX idx_medadmin_status ON medication_administration(status);
CREATE INDEX idx_medadmin_sched_dt ON medication_administration(scheduled_datetime);
CREATE INDEX idx_medadmin_barcode_verified ON medication_administration(barcode_verified);
Terminology Bindings
| Field |
Terminology |
Example Value |
drug_code_rxnorm |
RxNorm |
1049630 |
dose_unit |
UCUM |
mg |
route |
SNOMED CT / HL7 Route Codes |
IV, PO |
site |
SNOMED CT body structure |
368209003 (Left deltoid region) |
FHIR Resource Mapping
| Table Field |
FHIR Resource |
FHIR Path |
admin_id |
MedicationAdministration |
MedicationAdministration.id |
patient_id |
MedicationAdministration |
MedicationAdministration.subject.reference |
encounter_id |
MedicationAdministration |
MedicationAdministration.context.reference |
order_id |
MedicationAdministration |
MedicationAdministration.request.reference |
drug_code_rxnorm |
MedicationAdministration |
MedicationAdministration.medicationCodeableConcept.coding[RxNorm].code |
scheduled_datetime |
MedicationAdministration |
MedicationAdministration.effectivePeriod.start |
actual_datetime |
MedicationAdministration |
MedicationAdministration.effectiveDateTime |
dose_given, dose_unit |
MedicationAdministration |
MedicationAdministration.dosage.dose |
route |
MedicationAdministration |
MedicationAdministration.dosage.route |
site |
MedicationAdministration |
MedicationAdministration.dosage.site |
administered_by |
MedicationAdministration |
MedicationAdministration.performer.actor |
status |
MedicationAdministration |
MedicationAdministration.status |
barcode_verified |
MedicationAdministration |
Extension for barcode verification result |
prn_indication, prn_response |
MedicationAdministration |
MedicationAdministration.reasonCode, MedicationAdministration.note |
Purpose
Defines facility-level formularies (e.g., main hospital, specialty hospital) and their lifecycle (active, retired). Header table for formulary items.
Field Specifications
| Field |
Type |
Nullable |
Default |
Constraint |
Description |
formulary_id |
BIGINT |
NO |
IDENTITY |
PK |
Formulary identifier |
formulary_name |
VARCHAR(100) |
NO |
— |
Unique per facility |
Name (e.g., "Main Hospital Adult Formulary") |
facility_id |
BIGINT |
NO |
— |
FK → facilities.facility_id |
Facility |
effective_date |
DATE |
NO |
CURRENT_DATE |
— |
Start date |
end_date |
DATE |
YES |
NULL |
> effective_date |
End date if retired |
approved_by |
BIGINT |
NO |
— |
FK → users.user_id |
Chief pharmacist/director |
status |
VARCHAR(20) |
NO |
'active' |
IN ('draft','active','retired') |
Lifecycle status |
notes |
TEXT |
YES |
NULL |
— |
Additional notes |
created_at |
TIMESTAMP WITH TIME ZONE |
NO |
CURRENT_TIMESTAMP |
— |
Creation timestamp |
updated_at |
TIMESTAMP WITH TIME ZONE |
NO |
CURRENT_TIMESTAMP |
ON UPDATE |
Last update timestamp |
SQL DDL
SQLCREATE TABLE formulary (
formulary_id BIGINT GENERATED ALWAYS AS IDENTITY PRIMARY KEY,
formulary_name VARCHAR(100) NOT NULL,
facility_id BIGINT NOT NULL,
effective_date DATE NOT NULL DEFAULT CURRENT_DATE,
end_date DATE,
approved_by BIGINT NOT NULL,
status VARCHAR(20) NOT NULL DEFAULT 'active',
notes TEXT,
created_at TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT CURRENT_TIMESTAMP,
updated_at TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT CURRENT_TIMESTAMP,
CONSTRAINT uq_formulary_name_facility UNIQUE (formulary_name, facility_id)
);
ALTER TABLE formulary
ADD CONSTRAINT fk_formulary_facility
FOREIGN KEY (facility_id) REFERENCES facilities(facility_id) ON UPDATE CASCADE ON DELETE RESTRICT,
ADD CONSTRAINT fk_formulary_approved_by
FOREIGN KEY (approved_by) REFERENCES users(user_id) ON UPDATE CASCADE ON DELETE RESTRICT,
ADD CONSTRAINT chk_formulary_status
CHECK (status IN ('draft','active','retired')),
ADD CONSTRAINT chk_formulary_dates
CHECK (end_date IS NULL OR end_date > effective_date);
CREATE INDEX idx_formulary_facility_status ON formulary(facility_id, status);
FHIR Mapping
Formulary is not a core FHIR resource; map via Medication and List:
| Table Field |
FHIR Resource |
FHIR Path |
formulary_id |
List |
List.id |
formulary_name |
List |
List.title |
facility_id |
Organization |
List.managingEntity |
status |
List |
List.status |
effective_date, end_date |
List |
List.date / extensions |
Purpose
Defines individual medications within a formulary, including formulary status, restrictions, therapeutic class, and controlled substance schedule.
Field Specifications
| Field |
Type |
Nullable |
Default |
Constraint |
Description |
item_id |
BIGINT |
NO |
IDENTITY |
PK |
Formulary item |
formulary_id |
BIGINT |
NO |
— |
FK → formulary.formulary_id |
Parent formulary |
drug_code_rxnorm |
VARCHAR(20) |
NO |
— |
RxNorm |
Drug code |
drug_name |
VARCHAR(255) |
NO |
— |
— |
Display name |
generic_name |
VARCHAR(255) |
YES |
NULL |
— |
Generic name |
strength |
VARCHAR(50) |
YES |
NULL |
— |
Strength (e.g., 500 mg) |
dosage_form |
VARCHAR(50) |
YES |
NULL |
— |
Tablet, injection, etc. |
formulary_status |
VARCHAR(20) |
NO |
'on_formulary' |
IN ('on_formulary','non_formulary','restricted','obsolete') |
Status |
restriction_type |
VARCHAR(50) |
YES |
NULL |
— |
e.g., "ID approval", "Oncology only" |
therapeutic_class |
VARCHAR(50) |
YES |
NULL |
ATC code |
Therapeutic class |
therapeutic_alternative_rxnorm |
VARCHAR(20) |
YES |
NULL |
RxNorm |
Suggested alternative |
requires_prior_auth |
BOOLEAN |
NO |
FALSE |
— |
Insurance PA required |
is_high_alert |
BOOLEAN |
NO |
FALSE |
— |
High-alert medication flag |
is_controlled |
BOOLEAN |
NO |
FALSE |
— |
UAE MOH controlled substance |
controlled_schedule |
VARCHAR(20) |
YES |
NULL |
UAE MOH schedule |
Controlled classification |
default_route |
VARCHAR(30) |
YES |
NULL |
— |
Default route |
default_frequency |
VARCHAR(30) |
YES |
NULL |
— |
Default frequency |
default_dose |
NUMERIC(12,3) |
YES |
NULL |
≥ 0 |
Default dose |
default_dose_unit |
VARCHAR(20) |
YES |
NULL |
UCUM |
Default dose unit |
active_flag |
BOOLEAN |
NO |
TRUE |
— |
Active in formulary |
created_at |
TIMESTAMP WITH TIME ZONE |
NO |
CURRENT_TIMESTAMP |
— |
Creation timestamp |
updated_at |
TIMESTAMP WITH TIME ZONE |
NO |
CURRENT_TIMESTAMP |
ON UPDATE |
Last update timestamp |
SQL DDL
SQLCREATE TABLE formulary_items (
item_id BIGINT GENERATED ALWAYS AS IDENTITY PRIMARY KEY,
formulary_id BIGINT NOT NULL,
drug_code_rxnorm VARCHAR(20) NOT NULL,
drug_name VARCHAR(255) NOT NULL,
generic_name VARCHAR(255),
strength VARCHAR(50),
dosage_form VARCHAR(50),
formulary_status VARCHAR(20) NOT NULL DEFAULT 'on_formulary',
restriction_type VARCHAR(50),
therapeutic_class VARCHAR(50),
therapeutic_alternative_rxnorm VARCHAR(20),
requires_prior_auth BOOLEAN NOT NULL DEFAULT FALSE,
is_high_alert BOOLEAN NOT NULL DEFAULT FALSE,
is_controlled BOOLEAN NOT NULL DEFAULT FALSE,
controlled_schedule VARCHAR(20),
default_route VARCHAR(30),
default_frequency VARCHAR(30),
default_dose NUMERIC(12,3),
default_dose_unit VARCHAR(20),
active_flag BOOLEAN NOT NULL DEFAULT TRUE,
created_at TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT CURRENT_TIMESTAMP,
updated_at TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT CURRENT_TIMESTAMP
);
ALTER TABLE formulary_items
ADD CONSTRAINT fk_formulary_items_formulary
FOREIGN KEY (formulary_id) REFERENCES formulary(formulary_id) ON UPDATE CASCADE ON DELETE CASCADE,
ADD CONSTRAINT chk_formulary_items_status
CHECK (formulary_status IN ('on_formulary','non_formulary','restricted','obsolete')),
ADD CONSTRAINT chk_formulary_items_controlled_schedule
CHECK (is_controlled = FALSE OR controlled_schedule IS NOT NULL);
CREATE INDEX idx_formulary_items_formulary ON formulary_items(formulary_id);
CREATE INDEX idx_formulary_items_drug ON formulary_items(drug_code_rxnorm);
CREATE INDEX idx_formulary_items_status ON formulary_items(formulary_status) WHERE active_flag = TRUE;
Terminology Bindings
| Field |
Terminology |
Example Value |
drug_code_rxnorm |
RxNorm |
1049630 |
therapeutic_class |
ATC |
N02BE01 (paracetamol) |
default_dose_unit |
UCUM |
mg |
controlled_schedule |
UAE MOH Controlled Substance Schedules |
CDa-Narcotic |
FHIR Mapping
| Table Field |
FHIR Resource |
FHIR Path |
item_id |
Medication |
Medication.id |
drug_code_rxnorm |
Medication |
Medication.code.coding[RxNorm].code |
drug_name |
Medication |
Medication.code.text |
generic_name |
Medication |
Extension or Medication.code.text |
dosage_form |
Medication |
Medication.form |
strength |
Medication |
Medication.ingredient.strength (parsed) |
formulary_status |
Medication |
Extension for formulary status |
restriction_type |
Medication |
Extension for restriction |
is_controlled, controlled_schedule |
Medication |
UAE-specific extensions |
6. drug_interactions
Purpose
Knowledge base of drug–drug interactions used by CDS during order verification.
Field Specifications
| Field |
Type |
Nullable |
Default |
Constraint |
Description |
interaction_id |
BIGINT |
NO |
IDENTITY |
PK |
Interaction rule |
drug_a_rxnorm |
VARCHAR(20) |
NO |
— |
RxNorm |
First drug |
drug_b_rxnorm |
VARCHAR(20) |
NO |
— |
RxNorm |
Second drug |
severity |
VARCHAR(20) |
NO |
— |
IN ('contraindicated','major','moderate','minor') |
Severity |
description |
TEXT |
NO |
— |
— |
Description of interaction |
clinical_significance |
TEXT |
YES |
NULL |
— |
Clinical impact |
recommendation |
TEXT |
YES |
NULL |
— |
Recommended action |
evidence_level |
VARCHAR(20) |
YES |
NULL |
— |
e.g., "Level 1", "High" |
source |
VARCHAR(100) |
YES |
NULL |
— |
Vendor/source (FDB, Medi-Span, etc.) |
active_flag |
BOOLEAN |
NO |
TRUE |
— |
Active rule |
created_at |
TIMESTAMP WITH TIME ZONE |
NO |
CURRENT_TIMESTAMP |
— |
Creation timestamp |
updated_at |
TIMESTAMP WITH TIME ZONE |
NO |
CURRENT_TIMESTAMP |
ON UPDATE |
Last update timestamp |
SQL DDL
SQLCREATE TABLE drug_interactions (
interaction_id BIGINT GENERATED ALWAYS AS IDENTITY PRIMARY KEY,
drug_a_rxnorm VARCHAR(20) NOT NULL,
drug_b_rxnorm VARCHAR(20) NOT NULL,
severity VARCHAR(20) NOT NULL,
description TEXT NOT NULL,
clinical_significance TEXT,
recommendation TEXT,
evidence_level VARCHAR(20),
source VARCHAR(100),
active_flag BOOLEAN NOT NULL DEFAULT TRUE,
created_at TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT CURRENT_TIMESTAMP,
updated_at TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT CURRENT_TIMESTAMP,
CONSTRAINT uq_drug_interactions_pair UNIQUE (drug_a_rxnorm, drug_b_rxnorm)
);
ALTER TABLE drug_interactions
ADD CONSTRAINT chk_drug_interactions_severity
CHECK (severity IN ('contraindicated','major','moderate','minor'));
CREATE INDEX idx_drug_interactions_drug_a ON drug_interactions(drug_a_rxnorm) WHERE active_flag = TRUE;
CREATE INDEX idx_drug_interactions_drug_b ON drug_interactions(drug_b_rxnorm) WHERE active_flag = TRUE;
Terminology Bindings
| Field |
Terminology |
Example Value |
drug_a_rxnorm |
RxNorm |
1049630 |
drug_b_rxnorm |
RxNorm |
617314 |
FHIR Mapping
Interactions are typically exposed via DetectedIssue or CDS services:
| Table Field |
FHIR Resource |
FHIR Path |
interaction_id |
DetectedIssue |
DetectedIssue.id (when instantiated) |
severity |
DetectedIssue |
DetectedIssue.severity |
description |
DetectedIssue |
DetectedIssue.detail |
recommendation |
DetectedIssue |
DetectedIssue.mitigation.action |
7. pharmacy_inventory
Purpose
Tracks current stock levels of medications per facility and location (central pharmacy, satellites, ADCs), including lot and expiry for traceability and UAE MOH controlled substance compliance.
Field Specifications
| Field |
Type |
Nullable |
Default |
Constraint |
Description |
inventory_id |
BIGINT |
NO |
IDENTITY |
PK |
Inventory record |
drug_code_rxnorm |
VARCHAR(20) |
NO |
— |
RxNorm |
Drug |
ndc_code |
VARCHAR(20) |
YES |
NULL |
— |
Local pack code / GTIN |
facility_id |
BIGINT |
NO |
— |
FK → facilities.facility_id |
Facility |
location_id |
BIGINT |
NO |
— |
FK → locations.location_id |
Storage location (vault, ADC, shelf) |
lot_number |
VARCHAR(50) |
YES |
NULL |
— |
Lot/batch |
expiry_date |
DATE |
YES |
NULL |
— |
Expiry date |
quantity_on_hand |
NUMERIC(14,3) |
NO |
0 |
≥ 0 |
Current stock |
reorder_point |
NUMERIC(14,3) |
YES |
NULL |
≥ 0 |
Threshold for reorder |
par_level |
NUMERIC(14,3) |
YES |
NULL |
≥ 0 |
Target stock level |
last_count_date |
DATE |
YES |
NULL |
— |
Last physical count |
unit_cost |
NUMERIC(12,4) |
YES |
NULL |
≥ 0 |
Cost per unit |
is_controlled |
BOOLEAN |
NO |
FALSE |
— |
Controlled substance flag |
controlled_schedule |
VARCHAR(20) |
YES |
NULL |
— |
UAE MOH schedule |
active_flag |
BOOLEAN |
NO |
TRUE |
— |
Active inventory line |
created_at |
TIMESTAMP WITH TIME ZONE |
NO |
CURRENT_TIMESTAMP |
— |
Creation timestamp |
updated_at |
TIMESTAMP WITH TIME ZONE |
NO |
CURRENT_TIMESTAMP |
ON UPDATE |
Last update timestamp |
SQL DDL
SQLCREATE TABLE pharmacy_inventory (
inventory_id BIGINT GENERATED ALWAYS AS IDENTITY PRIMARY KEY,
drug_code_rxnorm VARCHAR(20) NOT NULL,
ndc_code VARCHAR(20),
facility_id BIGINT NOT NULL,
location_id BIGINT NOT NULL,
lot_number VARCHAR(50),
expiry_date DATE,
quantity_on_hand NUMERIC(14,3) NOT NULL DEFAULT 0,
reorder_point NUMERIC(14,3),
par_level NUMERIC(14,3),
last_count_date DATE,
unit_cost NUMERIC(12,4),
is_controlled BOOLEAN NOT NULL DEFAULT FALSE,
controlled_schedule VARCHAR(20),
active_flag BOOLEAN NOT NULL DEFAULT TRUE,
created_at TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT CURRENT_TIMESTAMP,
updated_at TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT CURRENT_TIMESTAMP
);
ALTER TABLE pharmacy_inventory
ADD CONSTRAINT fk_inventory_facility
FOREIGN KEY (facility_id) REFERENCES facilities(facility_id) ON UPDATE CASCADE ON DELETE RESTRICT,
ADD CONSTRAINT fk_inventory_location
FOREIGN KEY (location_id) REFERENCES locations(location_id) ON UPDATE CASCADE ON DELETE RESTRICT,
ADD CONSTRAINT chk_inventory_qty_nonnegative
CHECK (quantity_on_hand >= 0),
ADD CONSTRAINT chk_inventory_reorder_nonnegative
CHECK (reorder_point IS NULL OR reorder_point >= 0),
ADD CONSTRAINT chk_inventory_par_nonnegative
CHECK (par_level IS NULL OR par_level >= 0),
ADD CONSTRAINT chk_inventory_unit_cost_nonnegative
CHECK (unit_cost IS NULL OR unit_cost >= 0),
ADD CONSTRAINT chk_inventory_controlled_schedule
CHECK (is_controlled = FALSE OR controlled_schedule IS NOT NULL);
CREATE INDEX idx_inventory_drug_loc ON pharmacy_inventory(drug_code_rxnorm, facility_id, location_id);
CREATE INDEX idx_inventory_expiry ON pharmacy_inventory(expiry_date) WHERE active_flag = TRUE;
CREATE INDEX idx_inventory_controlled ON pharmacy_inventory(is_controlled) WHERE is_controlled = TRUE;
Terminology Bindings
| Field |
Terminology |
Example Value |
drug_code_rxnorm |
RxNorm |
1049630 |
controlled_schedule |
UAE MOH Controlled Substance Schedules |
CDb |
FHIR Mapping
Inventory is not directly represented in core FHIR; can be mapped to Medication + InventoryItem (if using R5) or custom extensions.
8. inventory_transactions
Purpose
Audit trail of all inventory movements (receipts, issues, returns, adjustments, transfers), supporting stock reconciliation and UAE MOH controlled substance tracking.
Field Specifications
| Field |
Type |
Nullable |
Default |
Constraint |
Description |
transaction_id |
BIGINT |
NO |
IDENTITY |
PK |
Transaction |
inventory_id |
BIGINT |
NO |
— |
FK → pharmacy_inventory.inventory_id |
Affected inventory line |
transaction_type |
VARCHAR(20) |
NO |
— |
IN ('receipt','issue','return','adjustment','transfer_out','transfer_in','waste') |
Type |
quantity |
NUMERIC(14,3) |
NO |
— |
<> 0 |
Quantity change (positive or negative) |
from_location_id |
BIGINT |
YES |
NULL |
FK → locations.location_id |
Source location |
to_location_id |
BIGINT |
YES |
NULL |
FK → locations.location_id |
Destination location |
reference_type |
VARCHAR(30) |
YES |
NULL |
— |
e.g., order, invoice, reconciliation |
reference_id |
BIGINT |
YES |
NULL |
— |
ID in reference table (e.g., order_id) |
performed_by |
BIGINT |
NO |
— |
FK → users.user_id |
User performing transaction |
transaction_datetime |
TIMESTAMP WITH TIME ZONE |
NO |
CURRENT_TIMESTAMP |
— |
When performed |
reason |
VARCHAR(255) |
YES |
NULL |
— |
Reason (e.g., "expiry", "breakage") |
is_controlled |
BOOLEAN |
NO |
FALSE |
— |
Controlled substance flag snapshot |
created_at |
TIMESTAMP WITH TIME ZONE |
NO |
CURRENT_TIMESTAMP |
— |
Creation timestamp |
SQL DDL
SQLCREATE TABLE inventory_transactions (
transaction_id BIGINT GENERATED ALWAYS AS IDENTITY PRIMARY KEY,
inventory_id BIGINT NOT NULL,
transaction_type VARCHAR(20) NOT NULL,
quantity NUMERIC(14,3) NOT NULL,
from_location_id BIGINT,
to_location_id BIGINT,
reference_type VARCHAR(30),
reference_id BIGINT,
performed_by BIGINT NOT NULL,
transaction_datetime TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT CURRENT_TIMESTAMP,
reason VARCHAR(255),
is_controlled BOOLEAN NOT NULL DEFAULT FALSE,
created_at TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT CURRENT_TIMESTAMP
);
ALTER TABLE inventory_transactions
ADD CONSTRAINT fk_inv_tx_inventory
FOREIGN KEY (inventory_id) REFERENCES pharmacy_inventory(inventory_id) ON UPDATE CASCADE ON DELETE RESTRICT,
ADD CONSTRAINT fk_inv_tx_from_location
FOREIGN KEY (from_location_id) REFERENCES locations(location_id) ON UPDATE CASCADE ON DELETE SET NULL,
ADD CONSTRAINT fk_inv_tx_to_location
FOREIGN KEY (to_location_id) REFERENCES locations(location_id) ON UPDATE CASCADE ON DELETE SET NULL,
ADD CONSTRAINT fk_inv_tx_performed_by
FOREIGN KEY (performed_by) REFERENCES users(user_id) ON UPDATE CASCADE ON DELETE RESTRICT,
ADD CONSTRAINT chk_inv_tx_type
CHECK (transaction_type IN ('receipt','issue','return','adjustment','transfer_out','transfer_in','waste')),
ADD CONSTRAINT chk_inv_tx_quantity_nonzero
CHECK (quantity <> 0);
CREATE INDEX idx_inv_tx_inventory ON inventory_transactions(inventory_id);
CREATE INDEX idx_inv_tx_datetime ON inventory_transactions(transaction_datetime);
CREATE INDEX idx_inv_tx_type ON inventory_transactions(transaction_type);
CREATE INDEX idx_inv_tx_controlled ON inventory_transactions(is_controlled) WHERE is_controlled = TRUE;
9. controlled_substance_log
Purpose
Perpetual inventory and chain-of-custody log for controlled substances, compliant with UAE MOH requirements (Federal Law No. 14 of 1995 and amendments). Captures all movements, administration, and waste with dual signatures where required.
Field Specifications
| Field |
Type |
Nullable |
Default |
Constraint |
Description |
log_id |
BIGINT |
NO |
IDENTITY |
PK |
Log entry |
inventory_id |
BIGINT |
YES |
NULL |
FK → pharmacy_inventory.inventory_id |
Related inventory line |
drug_code_rxnorm |
VARCHAR(20) |
NO |
— |
RxNorm |
Drug |
controlled_schedule |
VARCHAR(20) |
NO |
— |
UAE MOH schedule |
Controlled class |
transaction_type |
VARCHAR(20) |
NO |
— |
IN ('receipt','dispense_to_unit','return_to_pharmacy','administer_to_patient','waste','adjustment','loss_theft') |
Type |
quantity |
NUMERIC(14,3) |
NO |
— |
> 0 |
Quantity involved |
balance_after |
NUMERIC(14,3) |
NO |
— |
≥ 0 |
Balance after transaction |
from_user_id |
BIGINT |
YES |
NULL |
FK → users.user_id |
From user (e.g., pharmacist) |
to_user_id |
BIGINT |
YES |
NULL |
FK → users.user_id |
To user (e.g., nurse) |
witness_id |
BIGINT |
YES |
NULL |
FK → users.user_id |
Witness for handover |
patient_id |
BIGINT |
YES |
NULL |
FK → patients.patient_id |
Patient if administered |
encounter_id |
BIGINT |
YES |
NULL |
FK → encounters.encounter_id |
Encounter if administered |
waste_amount |
NUMERIC(14,3) |
YES |
NULL |
≥ 0 |
Amount wasted |
waste_witnessed_by |
BIGINT |
YES |
NULL |
FK → users.user_id |
Witness for waste |
location_id |
BIGINT |
NO |
— |
FK → locations.location_id |
Vault/ADC/ward |
transaction_datetime |
TIMESTAMP WITH TIME ZONE |
NO |
CURRENT_TIMESTAMP |
— |
When occurred |
reason |
VARCHAR(255) |
YES |
NULL |
— |
Reason (e.g., "partial dose", "breakage") |
reported_to_moh |
BOOLEAN |
NO |
FALSE |
— |
Flag if reported (loss/theft) |
moh_report_reference |
VARCHAR(50) |
YES |
NULL |
— |
MOH report ID |
created_at |
TIMESTAMP WITH TIME ZONE |
NO |
CURRENT_TIMESTAMP |
— |
Creation timestamp |
SQL DDL
SQLCREATE TABLE controlled_substance_log (
log_id BIGINT GENERATED ALWAYS AS IDENTITY PRIMARY KEY,
inventory_id BIGINT,
drug_code_rxnorm VARCHAR(20) NOT NULL,
controlled_schedule VARCHAR(20) NOT NULL,
transaction_type VARCHAR(20) NOT NULL,
quantity NUMERIC(14,3) NOT NULL,
balance_after NUMERIC(14,3) NOT NULL,
from_user_id BIGINT,
to_user_id BIGINT,
witness_id BIGINT,
patient_id BIGINT,
encounter_id BIGINT,
waste_amount NUMERIC(14,3),
waste_witnessed_by BIGINT,
location_id BIGINT NOT NULL,
transaction_datetime TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT CURRENT_TIMESTAMP,
reason VARCHAR(255),
reported_to_moh BOOLEAN NOT NULL DEFAULT FALSE,
moh_report_reference VARCHAR(50),
created_at TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT CURRENT_TIMESTAMP
);
ALTER TABLE controlled_substance_log
ADD CONSTRAINT fk_cslog_inventory
FOREIGN KEY (inventory_id) REFERENCES pharmacy_inventory(inventory_id) ON UPDATE CASCADE ON DELETE SET NULL,
ADD CONSTRAINT fk_cslog_from_user
FOREIGN KEY (from_user_id) REFERENCES users(user_id) ON UPDATE CASCADE ON DELETE SET NULL,
ADD CONSTRAINT fk_cslog_to_user
FOREIGN KEY (to_user_id) REFERENCES users(user_id) ON UPDATE CASCADE ON DELETE SET NULL,
ADD CONSTRAINT fk_cslog_witness
FOREIGN KEY (witness_id) REFERENCES users(user_id) ON UPDATE CASCADE ON DELETE SET NULL,
ADD CONSTRAINT fk_cslog_patient
FOREIGN KEY (patient_id) REFERENCES patients(patient_id) ON UPDATE CASCADE ON DELETE SET NULL,
ADD CONSTRAINT fk_cslog_encounter
FOREIGN KEY (encounter_id) REFERENCES encounters(encounter_id) ON UPDATE CASCADE ON DELETE SET NULL,
ADD CONSTRAINT fk_cslog_waste_witness
FOREIGN KEY (waste_witnessed_by) REFERENCES users(user_id) ON UPDATE CASCADE ON DELETE SET NULL,
ADD CONSTRAINT fk_cslog_location
FOREIGN KEY (location_id) REFERENCES locations(location_id) ON UPDATE CASCADE ON DELETE RESTRICT,
ADD CONSTRAINT chk_cslog_type
CHECK (transaction_type IN ('receipt','dispense_to_unit','return_to_pharmacy','administer_to_patient','waste','adjustment','loss_theft')),
ADD CONSTRAINT chk_cslog_quantity_positive
CHECK (quantity > 0),
ADD CONSTRAINT chk_cslog_balance_nonnegative
CHECK (balance_after >= 0),
ADD CONSTRAINT chk_cslog_waste_amount
CHECK (waste_amount IS NULL OR waste_amount >= 0);
CREATE INDEX idx_cslog_drug_loc ON controlled_substance_log(drug_code_rxnorm, location_id);
CREATE INDEX idx_cslog_datetime ON controlled_substance_log(transaction_datetime);
CREATE INDEX idx_cslog_patient ON controlled_substance_log(patient_id);
CREATE INDEX idx_cslog_type ON controlled_substance_log(transaction_type);
10. iv_admixture_orders
Purpose
Stores IV admixture compounding orders and preparation details for sterile products, including beyond-use dating and verification.
Field Specifications
| Field |
Type |
Nullable |
Default |
Constraint |
Description |
admixture_id |
BIGINT |
NO |
IDENTITY |
PK |
IV admixture record |
order_id |
BIGINT |
NO |
— |
FK → pharmacy_orders.order_id |
Parent order |
patient_id |
BIGINT |
NO |
— |
FK → patients.patient_id |
Patient |
encounter_id |
BIGINT |
NO |
— |
FK → encounters.encounter_id |
Encounter |
base_solution |
VARCHAR(100) |
NO |
— |
— |
Base solution (e.g., "NaCl 0.9% 100 mL") |
base_solution_rxnorm |
VARCHAR(20) |
YES |
NULL |
RxNorm |
Base solution code |
additive_drug |
VARCHAR(255) |
NO |
— |
— |
Additive drug name |
additive_drug_rxnorm |
VARCHAR(20) |
YES |
NULL |
RxNorm |
Additive code |
additive_dose |
NUMERIC(12,3) |
NO |
— |
> 0 |
Additive dose |
additive_dose_unit |
VARCHAR(20) |
NO |
— |
UCUM |
Dose unit |
concentration |
VARCHAR(50) |
YES |
NULL |
— |
e.g., "4 mg/mL" |
total_volume |
NUMERIC(12,3) |
NO |
— |
> 0 |
Final volume (mL) |
infusion_rate |
NUMERIC(12,3) |
YES |
NULL |
≥ 0 |
Rate (mL/h) |
beyond_use_datetime |
TIMESTAMP WITH TIME ZONE |
NO |
— |
> preparation_datetime |
BUD |
prepared_by |
BIGINT |
NO |
— |
FK → users.user_id |
Technician/pharmacist who prepared |
verified_by |
BIGINT |
NO |
— |
FK → users.user_id |
Pharmacist verifying |
preparation_datetime |
TIMESTAMP WITH TIME ZONE |
NO |
CURRENT_TIMESTAMP |
— |
When prepared |
status |
VARCHAR(20) |
NO |
'prepared' |
IN ('queued','in_progress','prepared','released','discarded') |
Status |
hood_location_id |
BIGINT |
YES |
NULL |
FK → locations.location_id |
Cleanroom/hood |
gravimetric_verification_json |
JSONB |
YES |
NULL |
— |
Data from gravimetric system |
label_printed |
BOOLEAN |
NO |
FALSE |
— |
Label printed |
created_at |
TIMESTAMP WITH TIME ZONE |
NO |
CURRENT_TIMESTAMP |
— |
Creation timestamp |
SQL DDL
SQLCREATE TABLE iv_admixture_orders (
admixture_id BIGINT GENERATED ALWAYS AS IDENTITY PRIMARY KEY,
order_id BIGINT NOT NULL,
patient_id BIGINT NOT NULL,
encounter_id BIGINT NOT NULL,
base_solution VARCHAR(100) NOT NULL,
base_solution_rxnorm VARCHAR(20),
additive_drug VARCHAR(255) NOT NULL,
additive_drug_rxnorm VARCHAR(20),
additive_dose NUMERIC(12,3) NOT NULL,
additive_dose_unit VARCHAR(20) NOT NULL,
concentration VARCHAR(50),
total_volume NUMERIC(12,3) NOT NULL,
infusion_rate NUMERIC(12,3),
beyond_use_datetime TIMESTAMP WITH TIME ZONE NOT NULL,
prepared_by BIGINT NOT NULL,
verified_by BIGINT NOT NULL,
preparation_datetime TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT CURRENT_TIMESTAMP,
status VARCHAR(20) NOT NULL DEFAULT 'prepared',
hood_location_id BIGINT,
gravimetric_verification_json JSONB,
label_printed BOOLEAN NOT NULL DEFAULT FALSE,
created_at TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT CURRENT_TIMESTAMP
);
ALTER TABLE iv_admixture_orders
ADD CONSTRAINT fk_iv_order
FOREIGN KEY (order_id) REFERENCES pharmacy_orders(order_id) ON UPDATE CASCADE ON DELETE RESTRICT,
ADD CONSTRAINT fk_iv_patient
FOREIGN KEY (patient_id) REFERENCES patients(patient_id) ON UPDATE CASCADE ON DELETE RESTRICT,
ADD CONSTRAINT fk_iv_encounter
FOREIGN KEY (encounter_id) REFERENCES encounters(encounter_id) ON UPDATE CASCADE ON DELETE RESTRICT,
ADD CONSTRAINT fk_iv_prepared_by
FOREIGN KEY (prepared_by) REFERENCES users(user_id) ON UPDATE CASCADE ON DELETE RESTRICT,
ADD CONSTRAINT fk_iv_verified_by
FOREIGN KEY (verified_by) REFERENCES users(user_id) ON UPDATE CASCADE ON DELETE RESTRICT,
ADD CONSTRAINT fk_iv_hood_location
FOREIGN KEY (hood_location_id) REFERENCES locations(location_id) ON UPDATE CASCADE ON DELETE SET NULL,
ADD CONSTRAINT chk_iv_status
CHECK (status IN ('queued','in_progress','prepared','released','discarded')),
ADD CONSTRAINT chk_iv_additive_dose_positive
CHECK (additive_dose > 0),
ADD CONSTRAINT chk_iv_total_volume_positive
CHECK (total_volume > 0),
ADD CONSTRAINT chk_iv_infusion_rate_nonnegative
CHECK (infusion_rate IS NULL OR infusion_rate >= 0),
ADD CONSTRAINT chk_iv_bud_after_prep
CHECK (beyond_use_datetime > preparation_datetime);
CREATE INDEX idx_iv_order ON iv_admixture_orders(order_id);
CREATE INDEX idx_iv_patient ON iv_admixture_orders(patient_id);
CREATE INDEX idx_iv_status ON iv_admixture_orders(status);
CREATE INDEX idx_iv_bud ON iv_admixture_orders(beyond_use_datetime);
11. pharmacy_interventions
Purpose
Documents clinical pharmacy interventions on orders (dose adjustments, therapy changes, clarifications), supporting quality metrics and regulatory reporting.
Field Specifications
| Field |
Type |
Nullable |
Default |
Constraint |
Description |
intervention_id |
BIGINT |
NO |
IDENTITY |
PK |
Intervention |
order_id |
BIGINT |
NO |
— |
FK → pharmacy_orders.order_id |
Related order |
patient_id |
BIGINT |
NO |
— |
FK → patients.patient_id |
Patient |
encounter_id |
BIGINT |
YES |
NULL |
FK → encounters.encounter_id |
Encounter |
pharmacist_id |
BIGINT |
NO |
— |
FK → users.user_id |
Pharmacist |
intervention_type |
VARCHAR(50) |
NO |
— |
e.g., "dose adjustment", "interaction prevention" |
Type |
description |
TEXT |
NO |
— |
— |
Description of issue |
recommendation |
TEXT |
YES |
NULL |
— |
Recommendation to prescriber |
prescriber_contacted |
BOOLEAN |
NO |
FALSE |
— |
Contacted flag |
prescriber_response |
VARCHAR(50) |
YES |
NULL |
— |
e.g., "accepted", "rejected", "pending" |
outcome |
VARCHAR(50) |
YES |
NULL |
— |
Clinical outcome if known |
intervention_datetime |
TIMESTAMP WITH TIME ZONE |
NO |
CURRENT_TIMESTAMP |
— |
When recorded |
time_spent_minutes |
INT |
YES |
NULL |
≥ 0 |
Time spent |
cds_triggered |
BOOLEAN |
NO |
FALSE |
— |
Triggered by CDS alert |
created_at |
TIMESTAMP WITH TIME ZONE |
NO |
CURRENT_TIMESTAMP |
— |
Creation timestamp |
SQL DDL
SQLCREATE TABLE pharmacy_interventions (
intervention_id BIGINT GENERATED ALWAYS AS IDENTITY PRIMARY KEY,
order_id BIGINT NOT NULL,
patient_id BIGINT NOT NULL,
encounter_id BIGINT,
pharmacist_id BIGINT NOT NULL,
intervention_type VARCHAR(50) NOT NULL,
description TEXT NOT NULL,
recommendation TEXT,
prescriber_contacted BOOLEAN NOT NULL DEFAULT FALSE,
prescriber_response VARCHAR(50),
outcome VARCHAR(50),
intervention_datetime TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT CURRENT_TIMESTAMP,
time_spent_minutes INT,
cds_triggered BOOLEAN NOT NULL DEFAULT FALSE,
created_at TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT CURRENT_TIMESTAMP
);
ALTER TABLE pharmacy_interventions
ADD CONSTRAINT fk_intervention_order
FOREIGN KEY (order_id) REFERENCES pharmacy_orders(order_id) ON UPDATE CASCADE ON DELETE RESTRICT,
ADD CONSTRAINT fk_intervention_patient
FOREIGN KEY (patient_id) REFERENCES patients(patient_id) ON UPDATE CASCADE ON DELETE RESTRICT,
ADD CONSTRAINT fk_intervention_encounter
FOREIGN KEY (encounter_id) REFERENCES encounters(encounter_id) ON UPDATE CASCADE ON DELETE SET NULL,
ADD CONSTRAINT fk_intervention_pharmacist
FOREIGN KEY (pharmacist_id) REFERENCES users(user_id) ON UPDATE CASCADE ON DELETE RESTRICT,
ADD CONSTRAINT chk_intervention_time_spent
CHECK (time_spent_minutes IS NULL OR time_spent_minutes >= 0);
CREATE INDEX idx_intervention_order ON pharmacy_interventions(order_id);
CREATE INDEX idx_intervention_patient ON pharmacy_interventions(patient_id);
CREATE INDEX idx_intervention_datetime ON pharmacy_interventions(intervention_datetime);
CREATE INDEX idx_intervention_type ON pharmacy_interventions(intervention_type);
12. medication_reconciliation
Purpose
Captures reconciliation actions at admission, transfer, and discharge, including comparison between home, inpatient, and discharge medications.
Field Specifications
| Field |
Type |
Nullable |
Default |
Constraint |
Description |
recon_id |
BIGINT |
NO |
IDENTITY |
PK |
Reconciliation record |
patient_id |
BIGINT |
NO |
— |
FK → patients.patient_id |
Patient |
encounter_id |
BIGINT |
NO |
— |
FK → encounters.encounter_id |
Encounter |
reconciliation_type |
VARCHAR(20) |
NO |
— |
IN ('admission','transfer','discharge') |
Type |
home_medication_rxnorm |
VARCHAR(20) |
YES |
NULL |
RxNorm |
Home med code |
home_medication_name |
VARCHAR(255) |
YES |
NULL |
— |
Home med name |
home_dose |
VARCHAR(50) |
YES |
NULL |
— |
Home dose (free text) |
home_route |
VARCHAR(30) |
YES |
NULL |
— |
Home route |
home_frequency |
VARCHAR(30) |
YES |
NULL |
— |
Home frequency |
source_of_information |
VARCHAR(50) |
YES |
NULL |
— |
e.g., "patient", "family", "community pharmacy" |
action_taken |
VARCHAR(20) |
YES |
NULL |
IN ('continue','hold','modify','discontinue','new') |
Action |
new_order_id |
BIGINT |
YES |
NULL |
FK → pharmacy_orders.order_id |
New/modified order |
discrepancy_type |
VARCHAR(50) |
YES |
NULL |
— |
e.g., "omission", "duplication" |
reconciled_by |
BIGINT |
NO |
— |
FK → users.user_id |
Pharmacist/physician |
reconciled_datetime |
TIMESTAMP WITH TIME ZONE |
NO |
CURRENT_TIMESTAMP |
— |
When reconciled |
notes |
TEXT |
YES |
NULL |
— |
Additional notes |
created_at |
TIMESTAMP WITH TIME ZONE |
NO |
CURRENT_TIMESTAMP |
— |
Creation timestamp |
SQL DDL
SQLCREATE TABLE medication_reconciliation (
recon_id BIGINT GENERATED ALWAYS AS IDENTITY PRIMARY KEY,
patient_id BIGINT NOT NULL,
encounter_id BIGINT NOT NULL,
reconciliation_type VARCHAR(20) NOT NULL,
home_medication_rxnorm VARCHAR(20),
home_medication_name VARCHAR(255),
home_dose VARCHAR(50),
home_route VARCHAR(30),
home_frequency VARCHAR(30),
source_of_information VARCHAR(50),
action_taken VARCHAR(20),
new_order_id BIGINT,
discrepancy_type VARCHAR(50),
reconciled_by BIGINT NOT NULL,
reconciled_datetime TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT CURRENT_TIMESTAMP,
notes TEXT,
created_at TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT CURRENT_TIMESTAMP
);
ALTER TABLE medication_reconciliation
ADD CONSTRAINT fk_recon_patient
FOREIGN KEY (patient_id) REFERENCES patients(patient_id) ON UPDATE CASCADE ON DELETE RESTRICT,
ADD CONSTRAINT fk_recon_encounter
FOREIGN KEY (encounter_id) REFERENCES encounters(encounter_id) ON UPDATE CASCADE ON DELETE RESTRICT,
ADD CONSTRAINT fk_recon_new_order
FOREIGN KEY (new_order_id) REFERENCES pharmacy_orders(order_id) ON UPDATE CASCADE ON DELETE SET NULL,
ADD CONSTRAINT fk_recon_user
FOREIGN KEY (reconciled_by) REFERENCES users(user_id) ON UPDATE CASCADE ON DELETE RESTRICT,
ADD CONSTRAINT chk_recon_type
CHECK (reconciliation_type IN ('admission','transfer','discharge')),
ADD CONSTRAINT chk_recon_action
CHECK (action_taken IS NULL OR action_taken IN ('continue','hold','modify','discontinue','new'));
CREATE INDEX idx_recon_patient ON medication_reconciliation(patient_id);
CREATE INDEX idx_recon_encounter ON medication_reconciliation(encounter_id);
CREATE INDEX idx_recon_type ON medication_reconciliation(reconciliation_type);
CREATE INDEX idx_recon_datetime ON medication_reconciliation(reconciled_datetime);
13. antimicrobial_stewardship_reviews
Purpose
Tracks antimicrobial stewardship reviews, recommendations, and prescriber responses, including linkage to culture/sensitivity results from LIS.
Field Specifications
| Field |
Type |
Nullable |
Default |
Constraint |
Description |
review_id |
BIGINT |
NO |
IDENTITY |
PK |
Review |
order_id |
BIGINT |
NO |
— |
FK → pharmacy_orders.order_id |
Antimicrobial order |
patient_id |
BIGINT |
NO |
— |
FK → patients.patient_id |
Patient |
encounter_id |
BIGINT |
YES |
NULL |
FK → encounters.encounter_id |
Encounter |
antibiotic_rxnorm |
VARCHAR(20) |
NO |
— |
RxNorm |
Antibiotic |
review_type |
VARCHAR(20) |
NO |
— |
IN ('prospective','retrospective','automatic') |
Type |
indication |
VARCHAR(255) |
YES |
NULL |
— |
Indication (e.g., "HAP", "UTI") |
culture_result_id |
BIGINT |
YES |
NULL |
— |
LIS culture ID (external reference) |
recommendation |
TEXT |
YES |
NULL |
— |
Stewardship recommendation |
accepted |
BOOLEAN |
YES |
NULL |
— |
Whether prescriber accepted |
reviewed_by |
BIGINT |
NO |
— |
FK → users.user_id |
Stewardship pharmacist/ID physician |
reviewed_datetime |
TIMESTAMP WITH TIME ZONE |
NO |
CURRENT_TIMESTAMP |
— |
When reviewed |
prescriber_response |
VARCHAR(255) |
YES |
NULL |
— |
Prescriber comments |
ddd_value |
NUMERIC(10,3) |
YES |
NULL |
≥ 0 |
Defined daily doses for utilization metrics |
created_at |
TIMESTAMP WITH TIME ZONE |
NO |
CURRENT_TIMESTAMP |
— |
Creation timestamp |
SQL DDL
SQLCREATE TABLE antimicrobial_stewardship_reviews (
review_id BIGINT GENERATED ALWAYS AS IDENTITY PRIMARY KEY,
order_id BIGINT NOT NULL,
patient_id BIGINT NOT NULL,
encounter_id BIGINT,
antibiotic_rxnorm VARCHAR(20) NOT NULL,
review_type VARCHAR(20) NOT NULL,
indication VARCHAR(255),
culture_result_id BIGINT,
recommendation TEXT,
accepted BOOLEAN,
reviewed_by BIGINT NOT NULL,
reviewed_datetime TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT CURRENT_TIMESTAMP,
prescriber_response VARCHAR(255),
ddd_value NUMERIC(10,3),
created_at TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT CURRENT_TIMESTAMP
);
ALTER TABLE antimicrobial_stewardship_reviews
ADD CONSTRAINT fk_steward_order
FOREIGN KEY (order_id) REFERENCES pharmacy_orders(order_id) ON UPDATE CASCADE ON DELETE RESTRICT,
ADD CONSTRAINT fk_steward_patient
FOREIGN KEY (patient_id) REFERENCES patients(patient_id) ON UPDATE CASCADE ON DELETE RESTRICT,
ADD CONSTRAINT fk_steward_encounter
FOREIGN KEY (encounter_id) REFERENCES encounters(encounter_id) ON UPDATE CASCADE ON DELETE SET NULL,
ADD CONSTRAINT fk_steward_reviewer
FOREIGN KEY (reviewed_by) REFERENCES users(user_id) ON UPDATE CASCADE ON DELETE RESTRICT,
ADD CONSTRAINT chk_steward_review_type
CHECK (review_type IN ('prospective','retrospective','automatic')),
ADD CONSTRAINT chk_steward_ddd_nonnegative
CHECK (ddd_value IS NULL OR ddd_value >= 0);
CREATE INDEX idx_steward_order ON antimicrobial_stewardship_reviews(order_id);
CREATE INDEX idx_steward_patient ON antimicrobial_stewardship_reviews(patient_id);
CREATE INDEX idx_steward_datetime ON antimicrobial_stewardship_reviews(reviewed_datetime);
CREATE INDEX idx_steward_review_type ON antimicrobial_stewardship_reviews(review_type);
Data Volume Estimates
Approximate for a 300-bed UAE hospital.
| Table |
Initial Rows (Year 1) |
Annual Growth |
Notes |
pharmacy_orders |
1,000,000 |
+1,000,000 / year |
High volume across inpatient/outpatient |
pharmacy_dispensing |
1,500,000 |
+1,500,000 / year |
Multiple fills per order |
medication_administration |
8,000,000 |
+8,000,000 / year |
Multiple administrations per day per patient |
formulary |
10 |
+2 / year |
Few formularies per facility |
formulary_items |
3,000 |
+300 / year |
Based on master data brief |
drug_interactions |
50,000 |
+5,000 / year |
From vendor updates |
pharmacy_inventory |
10,000 |
+1,000 / year |
Per facility/location/lot |
inventory_transactions |
500,000 |
+500,000 / year |
All movements |
controlled_substance_log |
50,000 |
+50,000 / year |
All controlled movements |
iv_admixture_orders |
80,000 |
+80,000 / year |
High for critical care/oncology |
pharmacy_interventions |
100,000 |
+100,000 / year |
Active clinical pharmacy |
medication_reconciliation |
120,000 |
+120,000 / year |
Per admission/transfer/discharge |
antimicrobial_stewardship_reviews |
40,000 |
+40,000 / year |
Restricted/broad-spectrum antibiotics |
Data Retention Policy (UAE Context)
Retention aligned with UAE MOH, DOH, DHA guidance and UAE PDPL (minimums; facilities may choose longer retention).
| Table |
Recommended Retention |
Rationale / Notes |
pharmacy_orders |
≥ 25 years from last encounter |
Core part of medical record; supports medico-legal and MOH audits |
pharmacy_dispensing |
≥ 15 years |
Medication history, billing disputes, HIE traceability |
medication_administration |
≥ 25 years |
Part of clinical record and nursing documentation |
formulary |
≥ 10 years after retirement |
Policy/audit trail for formulary decisions |
formulary_items |
≥ 10 years after retirement |
Supports retrospective clinical audits |
drug_interactions |
5 years after deactivation |
Knowledge base; keep for CDS auditability |
pharmacy_inventory |
10 years |
Stock management, recall traceability |
inventory_transactions |
10 years |
Financial and audit trail, especially for high-cost drugs |
controlled_substance_log |
≥ 15 years |
UAE MOH controlled substance regulations and potential investigations |
iv_admixture_orders |
≥ 15 years |
High-risk sterile preparations; supports adverse event investigations |
pharmacy_interventions |
≥ 15 years |
Quality metrics, medico-legal support |
medication_reconciliation |
≥ 25 years |
Part of longitudinal medication history |
antimicrobial_stewardship_reviews |
≥ 10 years |
Stewardship program reporting, resistance trend analysis |
Data older than the retention period should be archived in encrypted, access-controlled storage, with access governed by UAE PDPL (data minimisation, purpose limitation, and subject rights).