Team 03
Team 03
Project Report
MEDYSYNC Consulting
Medical patients have many records to keep track of, doctors prescribe many
different prescriptions each with numerous different fields like quantity and the brand
name of the medication, pharmacies and companies have their own agreements on
pricing and availability of their product and much more.
We here at MedySync wrote this database with the intent of helping with the
organization, storage, and retrieval of data that surrounds all of these important contact
points within the pharmaceutical and medical industry. The database records sensitive
information regarding patients like their primary care doctors, their related prescriptions,
and the link between those medications and what companies manufacture them, and
where those medications can be found in pharmacies. The database also utilizes a web
server to run a portal where patients can view their information and their doctors
information as well. New patients and doctors can add themselves to the database and
manage their info through it. Another use case, this database can assist companies with
their drug management by allowing them to check their presence in pharmacies through
their existing contracts, and by allowing them to see patients are currently taking the
medications. See below and on the next page for further detail about the database and
its connections.
Above is our ER diagram, depicting the linkage between the aforementioned tables. Primary keys are
shown with the yellow key icon, blue diamonds show non-null fields, red diamonds show foreign keys,
and any inner clear diamonds show potentially null fields.
Per the requirements, each patient has a unique identifying ID, a social security
number (SSN), full name, birthdate, full address represented in smaller fields like street
address and state etc. and their single primary care physician (stored as their doctor's
ID).
Their patientID is the primary key and is an autoincrementing INT, their SSN is
stored as VARCHAR(9) to record the numbers only (ignoring the dashes you commonly
see), VARCHAR(70) for full name to accommodate long names, and street, city, state,
zipcode as VARCHARS so we can do much more detailed searches like by patients in a
certain state or city. We represented their age as a birthdate so that we could
dynamically calculate their age depending on the current date.
The patient’s doctor’s ID is a foreign key that relates to the doctors table for their
personal doctor.
Each doctor has a unique ID, a SSN, full name, medical specialty, and their start
date for their practice.
For the same reasons as before, ID is the primary key, SSN is represented as
VARCHAR(9) and full name with VARCHAR(70). Their years of experience is
represented as a start year in INT form, so that you can dynamically calculate their
years of experience like birthdate previously. Lastly, their medical specialty is stored as
VARCHAR(70) to cover any long fields like ‘Physical medicine and rehabilitation.’
A doctor can be multiple patient’s personal doctors, so there’s no patient foreign
key in this table, that link is already covered.
A drug has a unique ID, a market trade name, a generic formula name, and the
ID of the company that manufactures it.
It’s drug_id is it’s primary key, the trade name, generic name, and company name
are all stored as VARCHAR(70) to allow for long names, and all three can be null.
The foreign key is the company ID and links to the manufacturer through the
company table as for each drug there is always only a single manufacturing company.
One constraint we noticed was that a drug’s price is only noted in a contract (see
further down) and one column we could add is a MSRP or market price for a drug.
A company contains a unique ID, their full company name and phone number. ID
is an AI INT, name is stored as a VARCHAR(70), & phone number is stored as
VARCHAR(10) to account for the numbers only (sans the parentheses/dashes you
sometimes see). The linkage is already handled in the drug table by CompanyName.
A pharmacy has a unique ID, a name for the store, an address, and a phone
number.
The ID is the primary key and is an auto incrementing unique INT, the
pharmacy's name stored as VARCHAR(70), its address stored as a VARCHAR(255),
and phone number as a VARCHAR(10).
There are no foreign keys and the link is handled in the contract table.
A contract contains a unique ID, a start/end date for the contract, a text
description, an agreed on price, the drug_id, the contracted pharmacy’s ID, and that
pharmacy's contract supervisor (stored as their ID).
The ContractID is an auto unique incrementing INT and is the primary key, both
the start/end date as a YYYY-MM-DD date, the contract’s description can be long so it is
stored as VARCHAR(255), the price of the drug in the contract is stored as a decimal
and can range from as small as 0.01 to 9999.99.
There are many foreign keys and linkages in this table and their data types have
been previously explained. The supervisor’s ID is a foreign key and links to the
supervisor table, the drug_id is the foreign key that links to the drug table, and the
pharmacyID links back to the pharmacy table.
-- -----------------------------------------------------
-- Schema bigpharma
-- -----------------------------------------------------
CREATE SCHEMA IF NOT EXISTS `bigpharma` DEFAULT CHARACTER SET utf8 ;
USE `bigpharma` ;
-- -----------------------------------------------------
-- Table `bigpharma`.`doctor`
-- -----------------------------------------------------
CREATE TABLE IF NOT EXISTS `bigpharma`.`doctor` (
`id` INT NOT NULL AUTO_INCREMENT,
`ssn` VARCHAR(9) NOT NULL,
`name` VARCHAR(70) NOT NULL,
`specialty` VARCHAR(70) NOT NULL,
`practice_since_year` INT NOT NULL,
PRIMARY KEY (`id`))
ENGINE = InnoDB;
-- -----------------------------------------------------
-- Table `bigpharma`.`patient`
-- -----------------------------------------------------
CREATE TABLE IF NOT EXISTS `bigpharma`.`patient` (
`patientID` INT NOT NULL AUTO_INCREMENT,
`name` VARCHAR(70) NOT NULL,
`birthdate` DATE NOT NULL,
`ssn` VARCHAR(9) NOT NULL,
`street` VARCHAR(70) NOT NULL,
`city` VARCHAR(70) NOT NULL,
`state` VARCHAR(45) NOT NULL,
`zipcode` VARCHAR(10) NOT NULL,
`primaryID` INT NOT NULL,
PRIMARY KEY (`patientID`),
INDEX `fk_patient_doctor_idx` (`primaryID` ASC) VISIBLE,
CONSTRAINT `fk_patient_doctor`
FOREIGN KEY (`primaryID`)
REFERENCES `bigpharma`.`doctor` (`id`)
ON DELETE NO ACTION
ON UPDATE NO ACTION)
ENGINE = InnoDB;
-- -----------------------------------------------------
-- Table `bigpharma`.`company`
-- -----------------------------------------------------
CREATE TABLE IF NOT EXISTS `bigpharma`.`company` (
`companyID` INT NOT NULL AUTO_INCREMENT,
`name` VARCHAR(70) NOT NULL,
`phone_number` VARCHAR(10) NOT NULL,
PRIMARY KEY (`companyID`))
ENGINE = InnoDB;
-- -----------------------------------------------------
-- Table `bigpharma`.`drug`
-- -----------------------------------------------------
CREATE TABLE IF NOT EXISTS `bigpharma`.`drug` (
`drug_id` INT(11) NOT NULL,
`trade_name` VARCHAR(45) NULL,
`formula` VARCHAR(45) NULL,
`companyID` INT NULL,
PRIMARY KEY (`drug_id`),
INDEX `fk_drug_company1_idx` (`companyID` ASC) VISIBLE,
CONSTRAINT `fk_drug_company1`
FOREIGN KEY (`companyID`)
REFERENCES `bigpharma`.`company` (`companyID`)
ON DELETE NO ACTION
ON UPDATE NO ACTION)
ENGINE = InnoDB;
-- -----------------------------------------------------
-- Table `bigpharma`.`pharmacy`
-- -----------------------------------------------------
CREATE TABLE IF NOT EXISTS `bigpharma`.`pharmacy` (
`pharmacyID` INT NOT NULL AUTO_INCREMENT,
`name` VARCHAR(70) NOT NULL,
`address` VARCHAR(70) NOT NULL,
`phone_number` VARCHAR(10) NOT NULL,
PRIMARY KEY (`pharmacyID`))
ENGINE = InnoDB;
-- -----------------------------------------------------
-- Table `bigpharma`.`prescription`
-- -----------------------------------------------------
CREATE TABLE IF NOT EXISTS `bigpharma`.`prescription` (
`rxid` INT NOT NULL AUTO_INCREMENT,
`drug_id` INT(11) NOT NULL,
`quantity` INT NOT NULL,
`prescribed_date` DATE NOT NULL,
`patientID` INT NOT NULL,
`doctor_id` INT NOT NULL,
`pharmacyID` INT NULL,
`date_filled` DATE NULL,
`cost` DECIMAL(7,2) NULL,
PRIMARY KEY (`rxid`),
INDEX `fk_prescription_drug1_idx` (`drug_id` ASC) VISIBLE,
INDEX `fk_prescription_patient1_idx` (`patientID` ASC) VISIBLE,
INDEX `fk_prescription_doctor1_idx` (`doctor_id` ASC) VISIBLE,
INDEX `fk_prescription_pharmacy1_idx` (`pharmacyID` ASC) VISIBLE,
CONSTRAINT `fk_prescription_drug1`
FOREIGN KEY (`drug_id`)
REFERENCES `bigpharma`.`drug` (`drug_id`)
ON DELETE NO ACTION
ON UPDATE NO ACTION,
CONSTRAINT `fk_prescription_patient1`
FOREIGN KEY (`patientID`)
REFERENCES `bigpharma`.`patient` (`patientID`)
ON DELETE NO ACTION
ON UPDATE NO ACTION,
CONSTRAINT `fk_prescription_doctor1`
FOREIGN KEY (`doctor_id`)
REFERENCES `bigpharma`.`doctor` (`id`)
ON DELETE NO ACTION
ON UPDATE NO ACTION,
CONSTRAINT `fk_prescription_pharmacy1`
FOREIGN KEY (`pharmacyID`)
REFERENCES `bigpharma`.`pharmacy` (`pharmacyID`)
ON DELETE NO ACTION
ON UPDATE NO ACTION)
ENGINE = InnoDB;
-- -----------------------------------------------------
-- Table `bigpharma`.`supervisor`
-- -----------------------------------------------------
CREATE TABLE IF NOT EXISTS `bigpharma`.`supervisor` (
`supervisorID` INT NOT NULL AUTO_INCREMENT,
`name` VARCHAR(70) NOT NULL,
`ssn` VARCHAR(9) NOT NULL,
PRIMARY KEY (`supervisorID`))
ENGINE = InnoDB;
-- -----------------------------------------------------
-- Table `bigpharma`.`contract`
-- -----------------------------------------------------
CREATE TABLE IF NOT EXISTS `bigpharma`.`contract` (
`contractID` INT NOT NULL AUTO_INCREMENT,
`start_date` DATE NOT NULL,
`end_date` DATE NOT NULL,
`text` VARCHAR(255) NOT NULL,
`price` DECIMAL(7,2) NOT NULL,
`supervisorID` INT NOT NULL,
`pharmacyID` INT NOT NULL,
`drug_id` INT(11) NOT NULL,
PRIMARY KEY (`contractID`),
INDEX `fk_contract_supervisor1_idx` (`supervisorID` ASC) VISIBLE,
INDEX `fk_contract_pharmacy1_idx` (`pharmacyID` ASC) VISIBLE,
INDEX `fk_contract_drug1_idx` (`drug_id` ASC) VISIBLE,
CONSTRAINT `fk_contract_supervisor1`
FOREIGN KEY (`supervisorID`)
REFERENCES `bigpharma`.`supervisor` (`supervisorID`)
ON DELETE NO ACTION
ON UPDATE NO ACTION,
CONSTRAINT `fk_contract_pharmacy1`
FOREIGN KEY (`pharmacyID`)
REFERENCES `bigpharma`.`pharmacy` (`pharmacyID`)
ON DELETE NO ACTION
ON UPDATE NO ACTION,
CONSTRAINT `fk_contract_drug1`
FOREIGN KEY (`drug_id`)
REFERENCES `bigpharma`.`drug` (`drug_id`)
ON DELETE NO ACTION
ON UPDATE NO ACTION)
ENGINE = InnoDB;
SET SQL_MODE=@OLD_SQL_MODE;
SET FOREIGN_KEY_CHECKS=@OLD_FOREIGN_KEY_CHECKS;
SET UNIQUE_CHECKS=@OLD_UNIQUE_CHECKS;
-- -----------------------------------------------------
-- There are missing inserts here, but those would take up too much space in
the report and are just in the included SQL schema file at the bottom instead.
-- -----------------------------------------------------
NORMALIZATION
During the process of creating the database we had to consider how data should
be managed and stored and how tables should be split up. Looking at the tables, we
implemented normalization by separating company and drug. This would be a case of
2NF (Second Normal Form) because the company is linked to the drug that it
manufactures while allowing there to be different drugs from many companies. A
second example of 2NF implementation would be the relation between the patient and
doctor tables because the database allows patients to have one doctor, but doctors can
have multiple patients with possibly the same name. In these cases normalization
allows for there to be multiple entries of either patients or drugs underneath one name
by using a key. After developing the database further along with a java application we
decided to normalize the address of a user by making separate columns for the street,
city, state, and zip. This was done because it allows for easier validation of the users
address and would allow us to do more powerful queries if need be.
QUERIES
This query is important because it allows a patient to find a pharmacy where they can
pick up their medications.
drug.drug_id;
“Display the total potential revenue to be gained from the medication when the drugs
are sold at the highest potential amount in a pharmacy”
This query is important because it can show a company their potential revenue if all
contracts had the maximum potential value such that they can pursue those contracts and
negotiate higher prices.
SELECT d.drug_id, SUM(cost * quantity)
FROM prescription outerc
JOIN drug d ON outerc.drug_id = d.drug_id
WHERE date_filled IS NULL
GROUP BY drug_id;
“Find all the pharmacies that don't carry your specific drug and provide a phone number
so you can contact them and make a contract with them.”
This query lets companies find missing contracts with pharmacies and provides a phone
number for the company so that they can contact the pharmacy if they want to create a contract
with them. Overall, boosting revenue by finding missing points of income.
“Find the patients who are taking similar medications and group them by medication
name.”
This query allows doctors and pharmacists to find which patients require what
medications. Pharmacists can view how much medication they should have on hand.
Display a count of how many patients that have been prescribed a drug have not picked
up their orders yet grouped by drug id.
This query is important because it shows companys the orders that have been unfulfilled
which are confirmed sources of revenue that have been unclaimed at the current query time.
Our data generate performs 1000 random patients, 10 random doctors, and 5000
random prescriptions where some are unfufilled still. Above is our confirmation that the
application has run successfully. Below is an example of what the database looks like
after prescriptions have generated.
Next we chose the ManagerReport file. For our input, we separated it to three
lines to make it easier for validating. Below is a screenshot of the ID validation working.
Further below that is an example of the output for a successful query from the database.
SPRING BOOT WEB SERVER
For our web applications we chose the patient lineup (newPatient, getPatient,
and updatePatient), so all of ControllerPatient. Through the web portal, we can register
a new user. Below is a screenshot of that in action and then our resulting patient_show.
Lastly is a screenshot of the database with our new values for our patient.
Below are screenshots of us attempting to enter invalid characters or even empty
values while updating our patient, we have similar checks for all fields in new patient as
well.
CONCLUSIONS
In summary, we have both learned a great deal from this project. We both
learned about how useful ER diagramming can be as well as how to set up tables with
them, we learned about the different linkages between tables while using an ER tool
and how this process also allows us to visualize if we need to normalize any tables or
not, we learned about how Java can interact with a database and on top of that how you
can implement a web server on top and create a functioning website that can handle
persistent user data. The diagramming required us to take into account which table
should handle what data, which further helped us understand the importance of the
tables and their placement. We learned how to normalize data and how to separate
fields into other tables to optimize our database. We also reinforced all of our previous
knowledge of SQL and its queries by having to come up with real world examples that
customers might be interested in. Apart from having to come up with examples, we also
had to implement the queries to validate that they worked. Overall, we believe it was a
very in depth learning opportunity with lots of hands on experience and really helped
solidify the essentials.