Join mysql table with distinct value from another table - mysql

I encountered a problem on a database I am working with. I have a table of counsels which may hold repeating values, but their is an enrolment number filed which is unique and can be used to fetch them. However, I want to join from a cases_counsel table on the "first" unique value of the counsel table that matches that column on the cases counsel table.
I want to list the cases belonging to a particular counsel using the enrolment_number as the counsel_id on the cp_cases_counsel table. That means I want to pick just a distinct value of a counsel, then use it to join the cp_cases_counsel table and also return the count for such.
However, I keep getting duplicates. This was the mysql query I tried
SELECT T.suitno, T.counsel_id, COUNT(*) as total from cp_cases_counsel T
INNER JOIN (SELECT
enrolment_number as id, MIN(counsel)
FROM
cp_counsel
GROUP BY
enrolment_number
) A
ON A.id = T.counsel_id
GROUP BY T.suitno, T.counsel_id
and
SELECT enrolment_number as id, MIN(counsel) as counsel, COUNT(*) as total FROM cp_counsel
JOIN cp_cases_counsel ON cp_cases_counsel.counsel_id = cp_counsel.enrolment_number
GROUP BY enrolment_number
For the second query, it's joining twice and I am having like double of what I am supposed to get.

The columns that you want in the results are councel (actually only one of all its values) from cp_counsel and counsel_id from cp_cases_counsel, so you must group by them and select them:
SELECT a.counsel, t.counsel_id, COUNT(*) AS total
FROM cp_cases_counsel t
INNER JOIN (
SELECT enrolment_number, MIN(counsel) AS counsel
FROM cp_counsel
GROUP BY enrolment_number
) a ON a.enrolment_number = t.counsel_id
GROUP BY a.counsel, t.counsel_id;

Related

MySQL order by keyword not working with insert into table from the inner join of two tables

Such is my MySQL query and the order by keyword isnt working here. Cannot figure out what's wrong with it.
insert into leaderboard
select student.student_name as name , sum(marks) as total
from marks inner join student on student.student_id = marks.student_id
group by marks.student_id order by total desc;
leaderboard table output image
Your current insert is not far off, though as a matter of practice, you should always explicitly list out the target columns for insertion, i.e. use this version:
INSERT INTO leaderboard (name, total) -- or whatever the column names are called
SELECT s.student_name, SUM(m.marks)
FROM marks m
INNER JOIN student s ON s.student_id = m.student_id
GROUP BY s.student_id;
Regarding the order you do or don't perceive in the leaderboard table, appreciate that SQL tables are modeled after unordered sets of data. That is, there is not really any inherent order in a SQL table. If you want to view your data in a certain order, then use an ORDER BY clause when you query (not when you insert):
SELECT name, total
FROM leaderboard
ORDER BY total DESC;

How can you LEFT JOIN a table to a table being joined ON a sub-select?

I am using the following query to join tables together and it seems to be working although I can't really understand why:
SELECT
listing.name,
biggestLot.price,
FROM Listings listing
LEFT JOIN Lots biggestLot ON biggestLot.lotNumber = (
SELECT lotNumber
FROM Lots
WHERE lotNumber IN
(
SELECT lotNumber
FROM Listings listingInner
WHERE listingInner.listingNumber = listing.listingNumber
)
ORDER BY size DESC
LIMIT 1
)
GROUP BY listing.listingNumber
The context is that each "Listing" is associated with one or more "Lots" through a "lotNumber" field. The tables aren't normalized; i.e. for any given Listing, there may be one or more rows in the "Listings" table that have duplicate values for all fields except for "lotNumber". The intent of the above query is to find the price of the biggest Lot associated with each Listing.
The inner SELECT is getting the largest Lot for a given Listing and I understand how that works. What I don't understand is how the LEFT JOIN merges the biggestLot result with the outer SELECT Listings query. I'm not specifying an ON field to combine the two tables so how does it know how to combine the results?
You could can use window functions along with the JOIN:
SELECT l.name, lo.price,
FROM Listings l LEFT JOIN
(SELECT lo.*,
ROW_NUMBER() OVER (PARITION BY lo.lotNumber ORDER BY lo.size DESC) as seqnum
FROM Lots lo
) lo
USING (lotNmber);

Selecting count(column) from different table

I have three tables area,vehicle and employee.
ward_no is the foreign key for vehicle and employee.
I want to select the number of vehicles and number of employees and display them along with other details of area.
The query i used is:
select a.* ,count(v.vid) as vehicles,count(e.eid) as employees from area a,vehicle v,employee e where v.ward_no=a.ward_no and e.ward_no=a.ward_no group by a.name;
But the output is not what I want. I get the same values in both the columns where the count is use instead of displaying the total number of vehicles/employees in that particular area.
I'm new to MySQl
The default behavior of count is to count the non-null values.
In your case, this counts repetitions of the value.
Try adding DISTINCT inside the count:
select a.* ,count(DISTINCT v.vid) as vehicles,count(DISTINCT e.eid) as employees
from area a,vehicle v,employee e
where v.ward_no=a.ward_no and e.ward_no=a.ward_no group by a.name;
Also, it's better to use explicit JOIN rather than implicit, like this:
select a.* ,count(DISTINCT v.vid) as vehicles,count(DISTINCT e.eid) as employees
from area a JOIN vehicle v ON v.ward_no=a.ward_no
JOIN employee e ON e.ward_no=a.ward_no
group by a.name;
There may be a chance that you are getting same vehicle and employee multiple times due to the joins, Use DISTINCT in COUNT() get count of unique vehicles and employees
SELECT
a.*,
COUNT(DISTINCT v.vid) AS vehicles,
COUNT(DISTINCT e.eid) AS employees
FROM
`area` a
JOIN vehicle v
ON v.ward_no = a.ward_no
JOIN employee e
ON e.ward_no = a.ward_no
GROUP BY a.name

Get a row which has the maximum id

Problem in simple words, 1st must be left joined to the 2nd table where the record is latest. So, I use an approach of using function MAX()
Currently I have 2 tables.
matches
matches_payments
|
Now I want to join the second table to first one using MAX(id) on matches_payments
Desired result
but I am not getting desired result due to greatest-n-per-group problem.
Query
SELECT matches.id, mp.*
FROM matches
LEFT JOIN (SELECT
MAX(id) AS id,
match_id
paymentStatus
FROM matches_payments
GROUP BY match_id) AS mp ON mp.id = matches.id;
Desired result is not produced due to : Stackoverflow Question
When using this feature, all rows in each group should have the same values for the columns that are ommitted from the GROUP BY part. The server is free to return any value from the group, so the results are indeterminate unless all values are the same.
FROM MySQL Dev
PS : I know the tables are poorly designed. It is not my work as the last developer did those.
You need two joins. You need a self-join of the matches_payments table to get the row with the highest ID for each match_id, as shown in SQL Select only rows with Max Value on a Column. Then you LEFT JOIN this to matches to combine the two tables:
SELECT m.*, mp.paymentStatus, mp.paymentAmount
FROM matches AS m
LEFT JOIN (
SELECT mp1.*
FROM matches_payments AS mp1
JOIN (SELECT match_id, MAX(id) AS id
FROM matches_payments
GROUP BY match_id) AS mp2
ON mp1.match_id = mp2.match_id AND mp1.id = mp2.id
) AS mp ON mp.match_id = m.id

Ordering MySQL table using timestamp from different table

I have two tables, group and groupAccess. One contains information for each "group", and the other contains all the times a group is accessed, including it's unique ID and timestamp.
My goal is to order all groups by the most recent time they were accessed.
I've got half way there, this query allows me to get all the groups in the correct order, however there are duplicate groups that I need to remove.
SELECT a.*
FROM groups a
INNER JOIN groupAccess b ON a.group_id = b.group_access_id
ORDER BY access_time DESC
I've tried using GROUP BY or DISTINCT, however this breaks the (currently) correct order of the groups. How can I fix this?
Use max() and GROUP BY to find the latest access time of each group, and then join that table with group. That is:
SELECT
a.*
, b.last_access_time
FROM
groups a
INNER JOIN (
select
group_access_id
, max(access_time) as last_access_time
from groupAccess
group by
group_access_id
) b ON a.group_id = b.group_access_id
ORDER BY b.last_access_time DESC