I have a database that holds a bunch of student information in the following tables
Student:
id
created_on
updated_on
StudentHistory
id
studentid
schoolid
gradeid
datestamp
active
The student history manages how students change over the years and allows me to report back student growth.
I now need to do the following query:
SELECT * FROM students
INNER JOIN studenthistory
ON student.id = studenthistory.studentid
WHERE studenthistory.active = 1
The problem is that the query won't necessarilly pull the latest history record like I need. Is there a way that I can guarentee that only the latest history record will get pulled in the join?
SELECT *
FROM students s
JOIN studentshistory sh
ON sh.id =
(
SELECT shi.id
FROM studentshistory shi
WHERE shi.studentid = s.id
AND shi.active = 1
ORDER BY
studentid DESC, active DESC, datestamp DESC, id DESC
LIMIT 1
)
Create an index on studentshistory (studentid, active, datestamp, id) for this to work fast.
I think this should work:
SELECT * FROM Students
INNER JOIN StudentHistory sh1
ON Student.studentid = sh1.studentid
AND StudentHistory.datestamp =
(SELECT MAX(datestamp)
FROM StudentHistory sh2
WHERE sh2.studentid = sh1.studentid);
Related
Schema
Researcher(ID (PK), )
Activity (PID (publication_FK, PK) , RID (researcher_FK , PK))
Publication (ID (PK) , Year)
PID , RID in Activity form its composite PK and each correspond to the FK of the Publication and Researcher tables, respectively
Query
For each researcher, who was has at least 2 publications, retrieve all their publications since the year 2000
Attempt
SELECT PID, RID
FROM Activity
WHERE RID IN (SELECT RID
FROM Activity
GROUP BY RID
HAVING COUNT(RID) >= 2)
How do I filter this interim result by Publication Year?
You need to join to publications. Using your approach:
SELECT a.PID, a.RID
FROM Activity a JOIN
Publications p
ON p.ID = a.PID
WHERE p.year >= 2000 AND
a.RID IN (SELECT a2.RID
FROM Activity a2
GROUP BY a2.RID
HAVING COUNT(*) >= 2
) ;
I have these tables:
tutors:
tutorid firstname, lastname...
courses:
url tutorid
reviews:
review courseid
I need to select all tutors that have the most reviews. 1 tutor = 1 course.
I first tried to just select courses with the most reviews:
select y.courseid, num from (select courseid,COUNT(reviews.rating) as num
from reviews group by (reviews.courseid)) y;
This selects all urls and the number of reviews for each.
this
select y.courseid, MAX(num) from (select courseid,COUNT(reviews.rating) as num
from reviews group by (reviews.courseid)) y;
would display the single course with most reviews - even if there are other courses with the same (maximum) number of reviews - they won't get displayed.
I'm trying to combat that. I tried
select y.courseid, num from (select courseid,COUNT(reviews.rating) as num
from reviews group by (reviews.courseid)) y
where num = MAX(num);
but get invalid use of group function error.
EDIT: the courseid - is the course's url. As in the course's url is the foreign key in the reviews table.
I would try this one:
select distinct t.tutorid t.firstname, t.lastname
from (select courseid, count(reviews.rating) total
from reviews
group by courseid) r
left join courses c
on r.courseid = c.courseid
left join tutors t
on c.tutorid = t.tutorid
where r.total=(select max(total)
from (select courseid,
count(reviews.rating) total
from reviews
group by courseid) r
)
You can create a column that rank the review in desc order and select those tutor with rank = 1
It would look like this:
Select * from(Select *, rank() over(order by num desc) as rank from table) where rank = 1
You can also use dense_rank base on your need.
I have a query problem that I previously solved with 2 tables and different db structure, and now I have 3 tables and I cant get the right result
leads table - regular leads table with id, firstname, etc...
statuses table - id, lead_id, brand_id, map_id
lead_id is relationship key for id in lead
map_id is relationship key for map_keys table
map_keys table - id, name, rank
the rules:
each lead can have more than one status or it can be without status
the query should print only the lowest status even if there is two or more statuses for the same lead
example:
lead: id = 3,
statuses: id = 7, lead_id = 3, map_id = 5
and another record:
statuses: id = 10, lead_id = 3, map_id = 1
map_keys:
id = 5, rank = 5
id = 1, rank = 1
in the result I should get
lead_id = 3, map_id = 1
In the past I had the rank within the statuses table, so my solution was
SELECT IF(s2.rank IS NULL, s.rank, s2.rank) AS rank FROM `leads` l
LEFT JOIN statuses s ON s.lead_id = l.id
LEFT JOIN statuses s2 ON s2.lead_id = s.lead_id AND s.rank > s2.rank
GROUP BY l.id
but with the new db structure I cant get the right result, I hope that my question is understandable, If not I will try my best to explain it better, Thanks!
I solved my problem, my final query is
SELECT * FROM leads
LEFT JOIN (
SELECT lead_id, mk.name, mk.rank FROM `statuses` s
JOIN map_keys mk ON mk.id = s.map_id
JOIN statuses_maps sm ON sm.id = s.status_id
ORDER BY rank ASC ) as s ON lead_id = lead.id
GROUP BY leads.id
I have 4 tables. One is called artist. Here is the table structure:
artistID lastname firstname nationality dateofbirth datedcease
The other table is called work
workId title copy medium description artist ID
Trans table
TransactionID Date Acquired Acquistionprice datesold
askingprice salesprice customerID workID
Customer table
customerID lastname Firstname street city state
zippostalcode country areacode phonenumber email
First question is which artist has the most works of artsold and how many of the artist works have been sold.
My SQL query is below
SELECT *
FROM dtoohey.artist A1
INNER JOIN
(SELECT
COUNT(W1.ArtistID) AS COUNTER, artistID
FROM dtoohey.trans T1
INNER JOIN dtoohey.work W1 ON W1.workid = T1.Workid
GROUP BY W1.artistID) TEMP1 ON TEMP1.artistID = A1.artistID
WHERE
A1.artistID = TEMP1.artistId
ORDER BY
COUNTER desc;
I am to get the whole table but I want to show only the first row which is the highest count - how do I do that??
qns 2 is sales of which artist's work have resulted in the highest average profit(i.e) the average of the profits made on each sale of worksby an artist), and what is that amount.
My SQL query is below
SELECT
A1.artistid, A1.firstname
FROM
(SELECT
(salesPrice - AcquisitionPrice) as profit,
w1.artistid as ArtistID
FROM dtoohey.trans T1
INNER JOIN dtoohey.WORK W1 ON W1.workid = T1.workid) TEMP1
INNER JOIN
dtoohey.artist A1 ON A1.artistID = TEMP1.artistID
GROUP BY
A1.artistid
HAVING
MAX(PROFIT) = AVG(PROFIT);
I'm not able to execute it
Use limit 1 for your fist question
Your second problem can be solved exactly the same as the first one. Just replace
COUNT(W1.ArtistID)
with
AVG(salesPrice - AcquisitionPrice) as AvgProfit
and then use:
ORDER BY AvgProfit DESC
LIMIT 1
The full query should be:
SELECT A1.artistid, A1.firstname, TEMP1.avgProfit
FROM (SELECT AVG(salesPrice - AcquisitionPrice) as avgProfit, W1.artistid as artistid
FROM dtoohey.trans T1
INNER JOIN dtoohey.WORK W1
ON W1.workid = T1.workid
GROUP BY artistid
ORDER BY avgProfit DESC
LIMIT 1) TEMP1
INNER JOIN dtoohey.artist A1
ON A1.artisid = TEMP1.artistid
I'm trying to create a single query containing optional aggregate values from multiple tables and having some difficulty. I'm going to try to simplify my problem to as few fields as possible.
Tables
applications
appid | pageid
contests
id | appid | winnerid
signups
id | contestid | firstname | lastname
referrals
id | signupid
tickets
id | signupid
Purpose of Query
I'm trying to combine the applications and contests tables based on the pageid parameter, join the signups table to get the winner when available, and then a count of all signups, referrals, and tickets or simply a zero value when none is available.
What I've got so far
SELECT t1.*, `Winner`.Name AS Winner, IFNULL(`srt`.Signups,0) AS Signups,
IFNULL(`srt`.Referrals,0) AS Referrals,
IFNULL(`srt`.Tickets,0) AS Tickets
FROM applications a, (contests c LEFT JOIN
/* Join signups table to retrieve winner's first/last name */
(SELECT id, contestid, CONCAT(firstname, ' ' , lastname) AS Name
FROM signups) `Winner`
ON c.winnerid = `Winner`.id
AND c.contestid = `Winner`.contestid) LEFT JOIN
/* Join signups, referrals, and tickets to retrieve counts */
(SELECT s.signupid, COUNT(*) AS Signups, Referrals, Tickets
FROM (signups s LEFT JOIN
(SELECT r.signupid, COUNT(r.id) AS Referrals
FROM signups s, referrals r
WHERE s.signupid = r.signupid) `Referrals`
ON s.signupid = `Referrals`.signupid) LEFT JOIN
(SELECT t.signupid, COUNT(t.id) AS Tickets
FROM signups s, tickets t
WHERE s.signupid = t.signupid) `Tickets`
ON s.signupid = `Tickets`.signupid) `srt`
ON signupid = `srt`.signupid
WHERE a.id = c.applicationid
AND a.pageid = #pageid
ORDER BY c.id IN (SELECT id FROM contests WHERE active = 1) desc, c.addeddate desc;
Problem
I'm positive this isn't the most efficient way to do what I'm trying to do and regardless it doesn't work. The values for the signups/referrals/tickets simply returns a count for every record in each of the tables. The winner join works fine, and if I limit it to just the signups, that works as well. The signups table is linked to the contests table, and then the referrals and tickets are related directly to the signups table. Any help on this complex query would be greatly appreciated.
Forgive me if I am misunderstanding, and also for my lack of knowledge of differences between MSSQL and mysql, but I would try something like this:
SELECT
( SELECT CONCAT(IFNULL(firstname,''), ' ' , IFNULL(lastname,''))
FROM Signups
WHERE id = c.winnerid) as Winner,
( SELECT COUNT(*)
FROM Signups
WHERE contestid = c.id) as Signups,
( SELECT COUNT(*)
FROM referrals r LEFT JOIN signups su ON r.signupid = su.id
WHERE su.contestid = c.id) as Referrals,
( SELECT COUNT(*)
FROM tickets t LEFT JOIN signups su ON t.signupid = su.id
WHERE su.contestid = c.id) as Tickets
FROM
Contests c