Inner join 3 tables and calculate the average value on a field - mysql

There are 3 tables:
medics:
IDM (id_medic) (primary key)
1st name
2nd name
specialty
patients:
IDP (id_patient) (primary key)
name
DOB (date of birth)
visits:
id
id_medic
id_patient
I would like to find out the average age of patients for each specialty.
SELECT specialty, AVG(year(curdate()) - year(patients.DOB))
FROM medics, patients, visits
WHERE medics.IDM = visits.medics GROUP by specialty;
The query above shows me on each line the average of all patients.

Try it:
SELECT
Speciality,
ROUND(AVG(YEAR(NOW())-YEAR(DOB)),0) AS Years
FROM visits
INNER JOIN medics
ON visits.IdMedic = medics.Id
INNER JOIN patients
ON visits.IdPatient = patients.Id
GROUP BY Speciality
My tables:
CREATE TABLE `visits` (
`Id` int(11) NOT NULL,
`IdMedic` int(11) DEFAULT NULL,
`IdPatient` int(11) DEFAULT NULL,
PRIMARY KEY (`Id`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1;
CREATE TABLE `patients` (
`Id` int(11) NOT NULL,
`Name` varchar(45) DEFAULT NULL,
`DOB` date DEFAULT NULL,
PRIMARY KEY (`Id`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1;
CREATE TABLE `medics` (
`Id` int(11) NOT NULL,
`Name` varchar(45) DEFAULT NULL,
`Speciality` varchar(45) DEFAULT NULL,
PRIMARY KEY (`Id`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1;

Related

sum function with join between two date ranges

hi friends i have two tables with name order and product order
CREATE TABLE `order` (
`order_num` int(11) NOT NULL AUTO_INCREMENT,
`date` date DEFAULT NULL,
`time` time DEFAULT NULL,
`cutomer_name` varchar(45) DEFAULT NULL,
PRIMARY KEY (`order_num`)
) ENGINE=InnoDB AUTO_INCREMENT=235 DEFAULT CHARSET=latin1
And
CREATE TABLE `product_order` (
`order_num` int(11) NOT NULL,
`idproduct` int(11) NOT NULL,
`quantity` tinyint(4) DEFAULT NULL,
`sub_price` int(11) DEFAULT NULL,
`price` int(11) DEFAULT NULL,
`actual_price` int(11) DEFAULT NULL,
PRIMARY KEY (`order_num`,`idproduct`),
KEY `fk_product_order_order1_idx` (`order_num`),
KEY `fk_product_order_product1_idx` (`idproduct`),
CONSTRAINT `fk_product_order_order1` FOREIGN KEY (`order_num`) REFERENCES `order` (`order_num`) ON DELETE NO ACTION ON UPDATE NO ACTION,
CONSTRAINT `fk_product_order_product1` FOREIGN KEY (`idproduct`) REFERENCES `product` (`idproduct`) ON DELETE NO ACTION ON UPDATE NO ACTION
) ENGINE=InnoDB DEFAULT CHARSET=latin1;
i want to join both table and want to retrieve the sum of product_order.actual_price,product_order.sub_price and product_order.quantity
between specific dates
my query return zero rows and i don't know how to solve this problem
here is my query
Select `order`.date,
Sum(product_order.actual_price) as actual_price_sum,
Sum(product_order.sub_price) as sub_price_sum,
Sum(product_order.quantity) as sold_quantity,
(Sum(product_order.sub_price)-Sum(product_order.actual_price)) as profit
From `order`
Inner Join product_order On `order`.order_num = product_order.order_num
WHERE CAST(`date` AS date) BETWEEN '2014-11-11' and '2015-11-11'
Group By `order`.date

Between a MIN and MAX date in joined table

I have a table called Booking and a table called FacilityBooking. A booking is a composition of facility bookings, a one to many relation. The date and time of the booking is determined by the lowest start date, and the highest end date of the facility bookings that belongs to it.
I want to pull some statistics of how many private and how many business bookings there has been between two dates.
CREATE TABLE `Booking` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`comments` varchar(255) DEFAULT NULL,
`createdBy` varchar(255) DEFAULT NULL,
`customerName` varchar(255) DEFAULT NULL,
`email` varchar(255) DEFAULT NULL,
`isPaid` bit(1) DEFAULT NULL,
`isPrivateClient` bit(1) DEFAULT NULL,
`needsPermission` bit(1) DEFAULT NULL,
`phoneNumber` varchar(255) DEFAULT NULL,
`referenceNumber` varchar(255) DEFAULT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
# Dump of table FacilityBooking
# ------------------------------------------------------------
CREATE TABLE `FacilityBooking` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`comments` varchar(2000) DEFAULT NULL,
`from` datetime DEFAULT NULL,
`to` datetime DEFAULT NULL,
`bookablePlace_id` int(11) DEFAULT NULL,
`booking_id` int(11) DEFAULT NULL,
PRIMARY KEY (`id`),
KEY `FK_2tv9w7g5vyx9po8vs6ceogldb` (`bookablePlace_id`),
KEY `FK_n17h188ecbdos5lsva51b8j29` (`booking_id`),
CONSTRAINT `FK_n17h188ecbdos5lsva51b8j29` FOREIGN KEY (`booking_id`) REFERENCES `Booking` (`id`),
CONSTRAINT `FK_2tv9w7g5vyx9po8vs6ceogldb` FOREIGN KEY (`bookablePlace_id`) REFERENCES `BookablePlace` (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
I have created an sqlfiddle: http://sqlfiddle.com/#!9/7ae95/2
And this is what i have so far:
SELECT
CASE isPrivateClient
WHEN 0 THEN "business"
WHEN 1 THEN "private"
END AS clientType,
count(isPrivateClient) as count
FROM
Booking
GROUP BY
isPrivateClient
So what i need from here is to join the facilitybookings and search between the lowest from date and the highest to date.
Hope someone can help me :)
Join the FacilityBooking table and filter using WHERE:
SELECT
CASE isPrivateClient
WHEN 0 THEN "business"
WHEN 1 THEN "private"
END AS clientType,
count(FacilityBooking.id) as count
FROM
Booking INNER JOIN FacilityBooking ON
Booking.id = FacilityBooking.booking_id
-- Between 2015-05-01 AND 2015-06-01 INCLUSSIVE'
WHERE FacilityBooking.from <= '2015-06-01' AND FacilityBooking.to >= '2015-05-01'
GROUP BY
isPrivateClient
fixed fiddle
If you want to only include "full" Booking in which all FacilityBooking are between 2 date, something like this should do the trick :
SELECT clientType, count(bookId)
FROM (
SELECT
b.id as bookId,
CASE b.isPrivateClient
WHEN 0 THEN "business"
WHEN 1 THEN "private"
END AS clientType,
Min(fb.from) as minFrom,
Max(fb.to) as maxTo
FROM
Booking b
INNER JOIN FacilityBooking fb ON b.id = fb.booking_id
GROUP BY bookId
) tbl
WHERE minFrom >= '2015-05-22' -- Min Date
AND maxTo <= '2015-05-24' -- Max Date
GROUP BY
clientType

MySQL: Find "last modified" date from two tables

I have two MySQL tables: tech_requests and comments. I want to display each tech_request one time in a list ordered by the "last modified" date, whether that be the date of the tech_request creation or the latest comment tied to that tech_request. I was trying to use UNION but I got stuck. Any ideas would be much appreciated. Here are the tables:
CREATE TABLE `tech_requests` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`staff_member_id` int(3) NOT NULL,
`date_time` datetime NOT NULL,
`request` text NOT NULL,
`building_id` int(2) NOT NULL,
`technician_id` int(2) DEFAULT NULL,
`completed` tinyint(1) NOT NULL,
`subject` varchar(30) NOT NULL DEFAULT '',
`category_id` int(2) NOT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=203 DEFAULT CHARSET=utf8;
CREATE TABLE `comments` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`tech_request_id` int(11) NOT NULL,
`technician_id` int(2) NOT NULL,
`date_time` datetime NOT NULL,
`comment` text NOT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=234 DEFAULT CHARSET=utf8;
Are you looking for something like this?
SELECT r.id, r.staff_member_id, ...,
GREATEST(r.date_time, COALESCE(c.date_time, 0)) last_modified
FROM tech_requests r LEFT JOIN
(
SELECT tech_request_id, MAX(date_time) date_time
FROM comments c
GROUP BY tech_request_id
) c
ON r.id = c.tech_request_id
ORDER BY last_modified
Here is SQLFiddle demo

how to create a team leaderboard with info from 4 tables?

This is tricky, I have been tasked with creating an team leader board where individuals complete tasks for a score. The score is defined in the table "station" and every time a user completes a task- a post is created in the posts table with the id of the station and their RFID (radio frequency ID). There is a team table which defines the team name.
i need a way to get the sum of all the post scores (joined points from stations table) a teams members have participated in.
The result should be sorted be team score and look something like if we have 4 teams with 4 members who participated in 4 events- whats the total score for each team
Team name one (Teams.name) | score
Team name two (Teams.name) | score
Team name three (Teams.name) | score
The tables -
CREATE TABLE `posts` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`rfid` varchar(50) NOT NULL,
`station_id` int(11) NOT NULL,
`updated_at` datetime NOT NULL,
`created_at` datetime NOT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1 AUTO_INCREMENT=11 ;
-- --------------------------------------------------------
Table structure for table stations
CREATE TABLE `stations` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`description` text NOT NULL,
`points` int(11) NOT NULL,
`logic` varchar(200) NOT NULL,
`created_at` datetime NOT NULL,
`updated_at` datetime NOT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1 AUTO_INCREMENT=1023 ;
-- --------------------------------------------------------
Table structure for table teams
CREATE TABLE `teams` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`name` varchar(255) NOT NULL,
`created_at` datetime NOT NULL,
`updated_at` datetime NOT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1 AUTO_INCREMENT=7 ;
-- --------------------------------------------------------
Table structure for table users
CREATE TABLE `users` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`rfid` varchar(50) NOT NULL,
`first_name` varchar(50) NOT NULL,
`last_name` varchar(50) NOT NULL,
`team` int(11) NOT NULL,
`quiz_score` int(11) NOT NULL,
`created_at` datetime NOT NULL,
`updated_at` datetime NOT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1 AUTO_INCREMENT=5 ;
I have created an query for an individual leaderboard-
SELECT users.first_name, users.last_name, posts.rfid, sum(stations.points) score
FROM posts
JOIN users ON posts.rfid = users.rfid
JOIN stations ON posts.station_id = stations.id
GROUP BY posts.rfid
ORDER BY score DESC LIMIT 0 , 100
this is what i have got so far for the team one
SELECT name, (SELECT sum(stations.points) score FROM posts
JOIN users ON posts.rfid = users.rfid
JOIN stations ON posts.station_id = stations.id
WHERE users.team = teams.id
GROUP BY posts.rfid) team_score FROM teams
//subquery returns more than one row
I think this might be the correct answer
SELECT name,
(SELECT sum(stations.points) score FROM posts
JOIN users ON posts.rfid = users.rfid
JOIN stations ON posts.station_id = stations.id
WHERE users.team = teams.id ) team_score
FROM teams

SQL query; inner join on 4 tables

Is this the most efficient way of joining these 4 tables? Also is it possible to only have some rows of each tables selected? I tried changing * to a name of a column but only the columns from studentlist are allowed.
SELECT c.classID, c.instrument, c.grade, u.ID, u.firstname, u.lastname, u.lastsongplayed, u.title
FROM studentlist s
INNER JOIN classlist c ON s.listID = c.classID
INNER JOIN (
SELECT *
FROM users u
INNER JOIN library l ON u.lastsongplayed = l.fileID
)
u ON s.studentID = u.ID
WHERE teacherID =3
ORDER BY classID
LIMIT 0 , 30
Database structure:
CREATE TABLE IF NOT EXISTS `classlist` (
`classID` int(11) NOT NULL AUTO_INCREMENT,
`teacherID` int(11) NOT NULL,
`instrument` text,
`grade` int(11) DEFAULT NULL,
PRIMARY KEY (`classID`),
KEY `teacherID_2` (`teacherID`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 AUTO_INCREMENT=27 ;
CREATE TABLE IF NOT EXISTS `studentlist` (
`listID` int(11) NOT NULL,
`studentID` int(11) NOT NULL,
KEY `teacherID` (`studentID`),
KEY `studentID` (`studentID`),
KEY `listID` (`listID`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
CREATE TABLE IF NOT EXISTS `users` (
`ID` int(11) NOT NULL AUTO_INCREMENT,
`email` varchar(60) NOT NULL,
`password` varchar(60) NOT NULL,
`firstname` text NOT NULL,
`lastname` text NOT NULL,
`sessionID` varchar(60) DEFAULT NULL,
`lastlogin` time DEFAULT NULL,
`registerdate` date NOT NULL,
`isteacher` tinyint(1) DEFAULT NULL,
`isstudent` tinyint(1) DEFAULT NULL,
`iscomposer` tinyint(1) DEFAULT NULL,
`lastsongplayed` int(11) NOT NULL,
PRIMARY KEY (`ID`),
UNIQUE KEY `ID` (`ID`),
UNIQUE KEY `email` (`email`,`sessionID`),
KEY `ID_2` (`ID`),
KEY `ID_3` (`ID`),
KEY `lastsongplayed` (`lastsongplayed`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 AUTO_INCREMENT=63 ;
CREATE TABLE IF NOT EXISTS `library` (
`fileID` int(11) NOT NULL AUTO_INCREMENT,
`userID` int(11) NOT NULL,
`uploaddate` datetime NOT NULL,
`title` varchar(60) NOT NULL,
`OrigComposer` varchar(60) NOT NULL,
`composer` varchar(60) NOT NULL,
`genre` varchar(60) DEFAULT NULL,
`year` year(4) DEFAULT NULL,
`arrangement` varchar(60) DEFAULT NULL,
PRIMARY KEY (`fileID`),
KEY `userID` (`userID`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 AUTO_INCREMENT=77 ;
Is this the most efficient way of joining these 3 tables?
Your JOIN looks correct and you are joining on your keys. So this should be efficient. However, I would encourage you to analyze your query with EXPLAIN to determine additional optimizations.
Is it possible to only have some rows of each tables selected?
Yes. Change * to be the columns from each table you want. I encourage you to explicitly prefix them with the originating table. Depending on the columns you select, this could also make your query more performant.
SELECT studentlist.studentID, users.email FROM ...