Group recursive 1:M relationship - mysql

I have a table with a recursive 1:M
Every customer may have been referred by a previous customer, now I want to group the customers who have made referrals, so I can display which ones have referred the most.
and I would want a query which gave following output
I tried
SELECT count(*) AS Count_of_referrals, referral_id
FROM Customer
GROUP BY referral_id
which gives the amount of times each referral_id is mentioned, but I can't find a way to link this back to the actual customer who referred them.
Appreciate any help I can get here.. :-)

Well, you're close. You just need to self join the customer table to get the name of the referral_id in there.
SELECT c1.referral_id,
c2.name,
count(*) count_of_referrals
FROM customer c1
INNER JOIN customer c2
ON c2.customer_id = c1.referral_id
GROUP BY c1.referral_id,
c2.name;

Related

Having trouble a query and specifically with joins

The code below is completely wrong and does not work at all. Im basically trying to look through my tables and compile a list of DeptName and the total student number for a department where a department has more than 40 students.
Im confused about joins in general and if someone could explain and show where im going wrong. im sure there is also other problems so any help with them would help
So basically one department is connected to one module, and a student is enrolled in a module. A student cannot take a module outside of their department. So each student should have one module that connects to one department
All of the ID fields in other tables are foreign keys as you can guess and changing the tables is not what I want to do here I just want to do this query as this stands
Relevant tables columns
Table Department DeptID, DeptName, Faculty, Address
Table Modules ModuleID, ModuleName, DeptID, Programme
Table Students StudentID,StudentName,DoB,Address,StudyType,`
Table Enrolments EID,StudentID,ModuleID,Semester,Year
SELECT Department.DeptName, COUNT(Student.StudentID) AS 'No of Students' FROM Department LEFT JOIN Module ON Department.DeptID= Module.DeptID LEFT JOIN Enrolment ON Module.ModuleID= Enrolment.StudentID LEFT JOIN Student.StudentID
GROUP BY(Department.DeptID)
HAVING COUNT(Student.StudentID)>=40
I have not included every table here as there are quite a lot.
But unless i've got this completely wrong you don't need to access a ModuleID in a staff table for the module they teach or something not relevant to this at all. As no student or Dept details are in there.
If that is the case i will fix it very quickly.
SELECT Department.DeptName, COUNT(Student.StudentID) AS 'No of Students'
FROM Department
LEFT JOIN Module
ON Department.DeptID= Module.DeptID
LEFT JOIN Enrolment
-- problem #1:
ON Module.ModuleID= Enrolment.StudentID
-- problem #2:
LEFT JOIN Student.StudentID
-- problem #3:
GROUP BY(Department.DeptID)
HAVING COUNT(Student.StudentID)>=40
You're joining these two tables using the wrong field. Generally when the modeling is done correctly, you should use USING instead of ON for joins
The right side of any JOIN operator has to be a table, not a column.
You have to group by every column in the select clause that is not part of an aggregate function like COUNT. I recommend that you select the DeptID instead of the name, then use the result of this query to look up the name in a subsequent select.
Note : Following code is untested.
WITH bigDepts AS (
SELECT DeptId, COUNT(StudentID) AS StudentCount
FROM Department
JOIN Module
USING ( DeptID )
JOIN Enrolment
USING ( ModuleID )
JOIN Student
USING ( StudentID )
GROUP BY DeptID
HAVING COUNT(StudentID)>=40
)
SELECT DeptID, DeptName, StudentCount
FROM Department
JOIN bigDepts
USING ( DeptID )
Instead of left join you need to use inner join since you need to select related rows only from those three tables.
Groupy by and having clause seems fine. Since you need departments with more than 40 students instead of >= please use COUNT(e.StudentID)>40
SELECT d.DeptName, COUNT(e.StudentID) AS 'No of Students' FROM Department d INNER JOIN Module m ON d.DeptID= m.DeptID inner JOIN Enrolment e ON m.ModuleID= e.StudentID LEFT JOIN Student.StudentID
GROUP BY(d.DeptName)
HAVING COUNT(e.StudentID)>40
So your join clause was a bit iffy to students as you wrote it, and presumably these should all be inner joins.
I've reformatted your query using aliases to make it easier to read.
Since you're counting the number of rows per DeptName you can simply do count(*), likewise in your having you are after counts greater than 40 only. Without seeing your schemas and data it's not possible to know if you might have duplicate Students, if that's the case and you want distinct students count can amend to count(distinct s.studentId)
select d.DeptName, Count(*) as 'No of Students'
from Department d
join Module m on m.DeptId=d.DeptId
join Enrolment e on e.StudentId=m.ModuleId
join Students s on s.StudentId=e.studentId
group by(d.DeptName)
having Count(*)>40
Also, looking at your join conditions, is the Enrolement table relevant?
select d.DeptName, Count(*) as 'No of Students'
from Department d
join Module m on m.DeptId=d.DeptId
join Students s on s.StudentId=m.moduleId
group by(d.DeptName)
having Count(*)>40

Retrieve information SELECET from tables

I want to retrieve information, specifically the names and the total number of unique activities of an athelete (which i've renamed "sports Variety". I want to rank first the athlete who does more activities, but I'm not sure how to approach this.
I also know I should use DISTINCT somewhere, but not sure where to put it. I also don't know how to sort by unique/most activities.
SELECT athlete.name, COUNT(athlete.name) AS 'Sports Variety' FROM athlete
INNER JOIN athlete ON athlete.id = training_session.activity GROUP BY
training_session.activity HAVING COUNT(athlete) > 0
I expect it to be 6 rows to be returned.
assuming you have two table one name athlete with athlete name and one name training_session for the activities related to each athletes
SELECT athlete.name, COUNT(*) AS 'Sports Variety'
FROM athlete
INNER JOIN training_session ON athlete.id = training_session.athlete_id
GROUP BY athlete.name
If you want to find the athlete having the most activities, you could try a LIMIT query:
SELECT
a.id,
a.name,
COUNT(*) AS num_activities
FROM athlete a
INNER JOIN training_session ts
ON a.id = ts.athelete_id
GROUP BY
a.id,
a.name
ORDER BY
COUNT(*) DESC
LIMIT 1;
I see a handful of syntax problems with your current query, such as the second table name is the same as the first (not what you want here). Note that my query doesn't handle the possibility that two or more athletes might happen to have the same amount of activity. To resolve that, we could either find something else to rank, or restructure the query.

Use SELECT through three table

I tried to write a query, but unfortunately I didn't succeed.
I want to know how many packages delivered over a given period by a person.
So I want to know how many packages were delivered by John (user_id = 1) between 01-02-18 and 28-02-18. John drives another car (another plate_id) every day.
(orders_drivers.user_id, plates.plate_name, orders.delivery_date, orders.package_amount)
I have 3 table:
orders with plate_id delivery_date package_amount
plates with plate_id plate_name
orders_drivers with plate_id plate_date user_id
I tried some solutions but didn't get the expected result. Thanks!
Try using JOINS as shown below:
SELECT SUM(o.package_amount)
FROM orders o INNER JOIN orders_drivers od
ON o.plate_id=od.plate_id
WHERE od.user_id=<the_user_id>;
See MySQL Join Made Easy for insight.
You can also use a subquery:
SELECT SUM(o.package_amount)
FROM orders o
WHERE EXISTS (SELECT 1
FROM orders_drivers od
WHERE user_id=<user_id> AND o.plate_id=od.plate_id);
SELECT sum(orders.package_amount) AS amount
FROM orders
LEFT JOIN plates ON orders.plate_id = orders_drivers.plate_id
LEFT JOIN orders_driver ON orders.plate_id = orders_drivers.plate_id
WHERE orders.delivery_date > date1 AND orders.delivery_date < date2 AND orders_driver.user_id = userid
GROUP BY orders_drivers.user_id
But seriously, you need to ask questions that makes more sense.
sum is a function to add all values that has been grouped by GROUP BY.
LEFT JOIN connects all tables by id = id. Any other join can do this in this case, as all ids are unique (at least I hope).
WHERE, where you give the dates and user.
And GROUP BY userid, so if there are more records of the same id, they are returned as one (and summed by their pack amount.)
With the AS, your result is returned under the name 'amount',
If you want the total of packageamount by user in a period, you can use this query:
UPDATE: add a where clause on user_id, to retrieve John related data
SELECT od.user_id
, p.plate_name
, SUM(o.package_amount) AS TotalPackageAmount
FROM orders_drivers od
JOIN plates p
ON o.plate_id = od.plate_id
JOIN orders o
ON o.plate_id = od.plate_id
WHERE o.delivery_date BETWEEN convert(datetime,01/02/2018,103) AND convert(datetime,28/02/2018,103)
AND od.user_id = 1
GROUP BY od.user_id
, p.plate_name
It groups rows on user_id and plate_name, filter a period of delivery_date(s) and then calculate the sum of packageamount for the group

How to display different columns from 2 tables with a subquery

I have 2 tables, which are related on a shared column customer_id:
customer
rental
I need to display the rental_id and last_update from the rental table.
Also the active column from the customer table where active is false
I have searched multiple websites, as well as several questions here on Stack Overflow and this is the closest I have gotten:
SELECT rental_id, last_update, active
FROM rental
WHERE customer_id IN
(SELECT customer_id
FROM customer
WHERE active = false);
Thank you in advance for any help.
Edit: I have to use a subquery as this is a school project so inner join answers do not help. Sorry.
Since the subquery only returns customers where active = false, there's no need to get that column from the table, you can just hard-code it into the SELECT list.
SELECT rental_id, last_update, false AS active
FROM rental
WHERE customer_id IN (
SELECT customer_id
FROM customer
WHERE active = false)
There's no way to get non-constant data from a table without it being one of the FROM or JOIN tables.
BTW, in my experience, MySQL is often very poor at optimizing WHERE c in (SELECT ...). I try to avoid them at all costs, and I think your teacher is misguided in prohibiting them.
Try a query like this. It use INNER JOIN instead of subselect
SELECT
r.rental_id,
r.last_update,
c.active
FROM rental r
INNER JOIN
customer c ON c.cusomer_id = r.customer_id
WHERE
c.active = FALSE;

MYSQL joining tables and selecting customer with no order for particular date

I am having trouble with this mysql query. I have a customer table and an orders table, linked by a customer ID. The orders table has a date field and I am trying to list the names of customers that do not have any orders for a particular month, July 2016. I was told a NOT IN might help but I'm not sure how to go about it. I looked for similar examples but they use IS NULL. I tried this but it did not like the NOT (not a valid input at this position:
SELECT customer.cust_name
FROM customer
LEFT JOIN ordertbl ON ordertbl.cust_id = customer.cust_id
WHERE order_date like '2016-07%' not in ordertbl.order_date;
I then tried this but it returned no results:
SELECT customer.cust_name
FROM customer
LEFT JOIN ordertbl ON ordertbl.cust_id = customer.cust_id
WHERE (SELECT COUNT(order_date like '2016-07%')) IS NULL;
I also found a similar example but couldn't get it, no results:
Select customer.cust_name
From customer
where ordertbl.cust_id Not in (
Select customer.cust_id
From ordertbl
Where ordertbl.order_date like '2016-07%');
I'm sure I'm going about this all wrong. I tried a few other examples but those didn't work either. Any help is appreciated.
Assuming that in the orders table, your customer ID reference is called CUSTOMER_ID, the query is:
SELECT CUSTOMER.CUST_NAME
FROM CUSTOMER
WHERE CUST_ID IN
(SELECT ORDERTBL.CUSTOMER_ID
FROM ORDERTBL
WHERE DATE <> yourdate)