Left join with count return one result - mysql

I have two tables.
|Table One: Adversitements-----------------------|
| ID | ADVTITLE |
|----|-------------------------------------------|
| 1 | IT Staff will be taken. |
| 2 | Human resources personnel will be taken. |
| 3 | CNC Operator will be taken. |
|Table Two: Applications-----|
| ID | ADVID | APPLICANTNAME |
|----|-------|---------------|
| 1 | 1 | John Doe |
| 2 | 1 | John Doe 2 |
| 3 | 1 | Jane Doe |
| 4 | 2 | John Doe |
| 5 | 2 | Jane Doe |
| 6 | 3 | John Doe |
I Want result:
| ADVTITLE | APPLICANTCOUNT |
|-------------------------------------------|----------------|
| IT Staff will be taken. | 3 |
| Human resources personnel will be taken. | 2 |
| CNC Operator will be taken. | 1 |
But returning a single result;
OUTPUT:
| ADVTITLE | APPLICANTCOUNT |
|-------------------------|----------------|
| IT Staff will be taken. | 6 |
MySQL Query;
SELECT adv.advtitle, COUNT(applications.id) as applicantCount
FROM advertisements as adv
LEFT JOIN applications
ON adv.id = applications.advid
All listings can be related to how the number of applicants?
SQL Fiddle Link: http://sqlfiddle.com/#!2/8644c/1/0

You missed the GROUP BY clause:
SELECT adv.advtitle, COUNT(applications.id) as applicantCount
FROM advertisements as adv
LEFT JOIN applications ON adv.id = applications.advid
GROUP BY adv.advtitle
ORDER BY applicantCount desc
Result:
ADVTITLE APPLICANTCOUNT
---------------------------------------------------------
IT Staff will be taken. 3
Human resources personnel will be taken.. 2
CNC Operator will be taken. 1
Fiddle Example

You need GROUP BY clause
SELECT adv.advtitle, COUNT(applications.id) as applicantCount
FROM advertisements as adv
LEFT JOIN applications
ON adv.id = applications.advid
GROUP BY applications.advid
SQL Fiddle

i already test it on my own try to paste it in your sqlfiddle :)
SELECT A.advtitle,COUNT(B.advid) AS ApplicantCount FROM advertisements A
LEFT JOIN applications B ON B.advid = A.id
GROUP BY A.id

Related

How to get all rows of one table after joining?

I have a database with 3 tables: students, courses and mistakes. I have one joining table (csm) where I connect the 3 tables. I am supposing mistakes are the same for each course.
Table Courses
+----------+---------------+
| crs_id | crs_name |
+----------+---------------+
| 1 | HTML |
| 2 | PHP |
| 3 | Python |
+----------+---------------+
Table Students
+----------+---------------+---------------+
| stu_id | stu_firstname | stu_lastname |
+----------+---------------+---------------+
| 1 | Tina | Turner |
| 2 | Lisa | Laroi |
| 3 | Dina | Donna |
| 3 | Jim | Leduc |
+----------+---------------+---------------+
Table Mistakes
+----------+---------------+------------+
| mis_id | mis_name | mis_weight |
+----------+---------------+------------+
| 1 | No camelCase | 7 |
| 2 | No brackets | 10 |
| 3 | Operator mist.| 12 |
+----------+---------------+------------+
Joining table CSM
+----------+------------+------------+------------+
| csm_id | fk_crs_id | fk_stu_id | fk_mis_id |
+----------+------------+------------+------------+
| 1 | 1 | 1 | 1 |
| 2 | 1 | 1 | 3 |
| 3 | 2 | 3 | 1 |
| 4 | 3 | 2 | 2 |
| 5 | 3 | 2 | 1 |
| 6 | 3 | 3 | 1 |
+----------+------------+------------+------------+
If I select a specific course, I want to get a list of ALL students with the minus points for this course. So I also want to get the students with no result in the joining table csm.
The closest result I got is with the following sql statement:
select stu_firsname, stu_lastname, csm.*, sum(mis_weight)
from students s
left join crs_stu_mis csm on s.stu_id = csm.fk_stu_id
left join mistakes m on csm.fk_mis_id = m.mis_id
where fk_crs_id = 4 or fk_crs_id is null
group by stu_firstname;
With this I get the sum of the mistakes for a certain course and also the students who don't have any records in CSM table, but some results are missing. For example, this doesn't show the students who have records in the CSM table, but not for the requested course.
How do I get these students in my result table?
In your query :
left join crs_stu_mis csm on s.stu_id = csm.fk_stu_id`
...
where fk_crs_id = 4 or fk_crs_id is null
This is not exactly what you want, since this condition will filter out students that have records in the csm table for only courses other than 4. You want to move that condition to the corresponding LEFT JOIN:
left join crs_stu_mis csm on s.stu_id = csm.fk_stu_id AND csm.fk_crs_id = 4
Another potential source of problems is the way the query handles aggregation. There are non-aggregated columns in the SELECT clause that do not appear in the GROUP BY clause. This syntax is not good SQL coding practice, and is not supported anymore since version 5.7 of MySQL. I assumed that you want to one record in the result for each student.
Query:
select
s.stu_firstname,
s.stu_lastname,
sum(m.mis_weight) total_misses_weight
from
students s
left join crs_stu_mis csm on s.stu_id = csm.fk_stu_id AND csm.fk_crs_id = 3
left join mistakes m on csm.fk_mis_id = m.mis_id
group by
s.stu_id,
s.stu_firstname,
s.stu_lastname
Demo on DB Fiddle for course id 3:
| stu_firstname | stu_lastname | total_misses_weight |
| ------------- | ------------ | ------------------- |
| Tina | Turner | |
| Lisa | Laroi | 17 |
| Dina | Donna | 7 |
| Jim | Leduc | |
if your primary data's is in CSM table, try this:
select s.stu_firsname, s.stu_lastname, csm.*, sum(m.mis_weight) from crs_stu_mis csm
join students s on s.stu_id = csm.fk_stu_id
join mistakes m on csm.fk_mis_id = m.fou_id
csm.fk_crs_id = 4
group by s.stu_naam;
Second case:
Your data's can affected by group by attribute, try attribute that it is not NULL , ex:
select s.stu_firsname, s.stu_lastname, csm.*, sum(m.mis_weight) from crs_stu_mis csm
join students s on s.stu_id = csm.fk_stu_id
join mistakes m on csm.fk_mis_id = m.fou_id
csm.fk_crs_id = 4
group by csm.csm_id;

school work delivery list mysql

I have two tables:
Table students and table of school work delivered
Students table
+--------------------------+---------------------------------+
| id | name |
+--------------------------+---------------------------------+
| 1 | ADAM |
| 2 | BRIGITTE |
| 3 | ANNE |
+--------------------------+---------------------------------+
table student works
+---------------+-------------------------+------------------+
| id_works | works | id_student |
+---------------+-------------------------+------------------+
| 1 | airplane wing | 1 |
| 2 | volcano | 2 |
| 3 | law of gravity | 1 |
| 4 | airplane wing | 3 |
| 5 | law of gravity | 1 |
+-----------------------------------------+------------------+
How do I make a SELECT for work that returns the entire list of students, indicating that the work is delivered? (IMPORTANT: list of all students)
Example
LIST FOR WORK **airplane wing**
+--------------------------+---------------------------------+
| ADAM | X |
| BRIGITTE | |
| ANNE | X |
+--------------------------+--------------------- -----------+
I have tried it with LEF JOIN and IF, but it is not the list of all the students without repeating them.
SELECT
s.name ,
w.work,
w.resid_id,
if(w.work = 'airplane wing', 'X', '') as mark
FROM students s
LEFT JOIN works w
ON s.id = w.id_student
ORDER BY s.name ASC
This will give you a list of all students
And fields id_works and works will be null for those who didn't complete the work
SELECT s.name, w.id_works, w.works
FROM students s
LEFT JOIN works w
ON (w.id_student = s.id AND w.works = 'airplane wing')
ORDER BY s.name ASC

SQL count rows of one table in relation to another table

I have 3 different tables :
Client
+----+-----------+----------+
| id | firstName | lastName |
+----+-----------+----------+
| 1 | John | Doe |
| 2 | Jane | Doe |
+----+-----------+----------+
Loan
+----+--------+-----------+----------------+
| id | amount | client_id | institution_id |
+----+--------+-----------+----------------+
| 1 | 200 | 2 | 3 |
| 2 | 400 | 1 | 1 |
+----+--------+-----------+----------------+
Institution
+----+---------------+
| id | name |
+----+---------------+
| 1 | Institution A |
| 2 | Institution B |
| 3 | Institution C |
+----+---------------+
I am looking to create a list of the number of loans a client has with each institution (for every row in the institution table). Including when a client has 0 loans with an institution.
Something that looks like :
+-----------+-----------+----------+--------------------------+-----------+
| client_id | firstName | lastName | financialInstitutionName | loanCount |
+-----------+-----------+----------+--------------------------+-----------+
| 1 | John | Doe | Institution A | 1 |
| 1 | John | Doe | Institution B | 0 |
| 1 | John | Doe | Institution C | 0 |
| 2 | Jane | Doe | Institution A | 0 |
| 2 | Jane | Doe | Institution B | 0 |
| 2 | Jane | Doe | Institution C | 1 |
+-----------+-----------+----------+--------------------------+-----------+
I have tried all manners of joins, subqueries and where clauses but without success. The concept that I do not grasp is how to get a row per institution, per client (total count institution x client). I would love if that query was possible without subqueries or union joins.
Thank you for your time!
First subquery in the FROM setups that data so each client has a record for each of the institutions. This is then joined to a subquery that counts the number of loans.
SELECT
d.client_id,
d.firstName,
d.lastName,
d.name AS financialInstitutionName,
CASE WHEN l IS NULL
THEN 0
ELSE l.loanCount
END AS loanCount
FROM
(
SELECT
Client.id AS client_id,
Client.firstName,
Client.lastName,
Institution.id AS institution_id,
Institution.name
FROM Client, Institution
) AS d
LEFT JOIN (
SELECT client_id, institution_id, COUNT(id) AS loanCount
FROM Loan
GROUP BY client_id, institution_id
) AS l ON d.client_id = l.client_id AND d.institution_id = l.institution_id
Edit: Includes a record for each institution
Edit: Spelling
SELECT
loan.client_id,
client.firstName,
client.lastName,
institution.name as financialInstitutionName,
COUNT(loan.id) as loanCount
FROM client
INNER JOIN loan ON client.id = loan.client_id
INNER JOIN institution ON loan.institution_id = institution.id
GROUP BY client.id;

MySQL Count Comma Delimited

I have 3 tables like this:
table_events
+------+----------+----------------------+
| ID | Title | Employees |
+------+----------+----------------------+
| 1 | Event1 | john,james |
+------+----------+----------------------+
| 2 | Event2 | sarah,jessica |
+------+----------+----------------------+
table_check_in
+------+----------+----------+---------------------+
| ID | Time | EventID | By |
+------+----------+----------+---------------------+
| 1 | 08:30 | 1 | john |
+------+----------+----------+---------------------+
| 2 | 08:30 | 1 | james |
+------+----------+----------+---------------------+
| 3 | 09:30 | 1 | john |
+------+----------+----------+---------------------+
| 4 | 10:30 | 2 | sarah |
+------+----------+----------+---------------------+
| 5 | 10:35 | 2 | sarah |
+------+----------+----------+---------------------+
table_problems
+------+----------------+----------+---------------------+
| ID | Comment | EventID | By |
+------+----------------+----------+---------------------+
| 1 | Broken door | 1 | john |
+------+----------------+----------+---------------------+
| 2 | Slippery floor | 1 | john |
+------+----------------+----------+---------------------+
| 3 | Leaking tap | 1 | john |
+------+----------------+----------+---------------------+
| 4 | Broken window | 2 | jessica |
+------+----------------+----------+---------------------+
| 5 | Broken glass | 2 | jessica |
+------+----------------+----------+---------------------+
I would like to print something like this:
+------+----------+---------------+-------------------+-------------------+
| ID | Title | Employees | Count_Check_In | Count_Problems |
+------+----------+---------------+-------------------+-------------------+
| 1 | Event1 | john,james | john:2,james:1 | john:3,james:0 |
+------+----------+---------------+-------------------+-------------------+
| 2 | Event2 | sarah,jessica | sarah:2,jessica:0 | sarah:0,jessica:2 |
+------+----------+---------------+-------------------+-------------------+
I know this problem would be trivial if the database was designed properly, but we don't have the luxury of an application rewrite at the moment.
You need to initially get all the employees for each event id from check in and problem tables by using a union.
Then left join the counts from each of check in and problems table to the previous result to get the 0 counts as well.
Finally use a group_concat to get the result in one row for each event id.
select te.id,te.title,te.employees
,group_concat(concat(t.`By`,':',coalesce(tccnt.cnt,0))) count_check_in
,group_concat(concat(t.`By`,':',coalesce(tpcnt.cnt,0))) count_problems
from table_events te
left join (select eventid,`By` from table_check_in
union
select eventid,`By`from table_problems) t on te.id = t.eventid
left join (select eventid,`By`,count(*) cnt from table_check_in group by eventid,`By`) tccnt on tccnt.eventid = t.eventid and tccnt.`By`=t.`By`
left join (select eventid,`By`,count(*) cnt from table_problems group by eventid,`By`) tpcnt on tpcnt.eventid = t.eventid and tpcnt.`By`=t.`By`
group by te.id,te.title,te.employees
Sample Demo (thanks to #valex for setting up the schema)
You can use GROUP_CONCAT to get a result. Here is an example. The only thing missed is employees with 0 check ins or problems.
SELECT ID, Title,Employees,
GROUP_CONCAT(DISTINCT CONCAT(check_in.`By`,':',check_in.cnt))
as Count_Check_In,
GROUP_CONCAT(DISTINCT CONCAT(problems.`By`,':',problems.cnt))
as Count_Problems
FROM table_events
LEFT JOIN (SELECT EventID,`By`, COUNT(*) as cnt
FROM table_check_in
GROUP BY EventID,`By`) as check_in
ON table_events.ID = check_in.EventID
LEFT JOIN (SELECT EventID,`By`, COUNT(*) as cnt
FROM table_problems
GROUP BY EventID,`By`) as problems
ON table_events.ID = problems.EventID
GROUP BY table_events.id
Demo

MySQL join and concat rows without repeating entries [duplicate]

This question already has answers here:
MySQL DISTINCT on a GROUP_CONCAT()
(6 answers)
Closed 6 years ago.
I have a question about how to merge multiple row output into one row without having the same entry multiple times.
The basic setup is 4 tables:
room
appointments
users
actions
And 2 intermediate tables:
actions_appointments
users_appointments
I post the exact structure of the tables at the end of my post.
Multiple appointments can be made for one entry in the room table (n:1), but one or more users can join appointments (n:n) and one or more actions can be performed (n:n).
The problem is that I don't know how to output a single appointment with each user and action only being displayed ONCE per appointment.
With the example tables at the bottom of this post I basically want this to be my output:
|----------------|-----------|---------------------|-------------|------------------------|
| appointment_id | room_name | datetime | actions | userfullnames |
|----------------|-----------|---------------------|-------------|------------------------|
| 1 | Studio | 2016-09-01 15:30:00 | work, sleep | John Doe, Martin Smith |
| 2 | Office | 2017-04-02 13:00:00 | sleep | John Doe |
|----------------|-----------|---------------------|-------------|------------------------|
But with the queue I came up with I get this:
|----------------|-----------|---------------------|-------------|------------------------|
| appointment_id | room_name | datetime | actions | userfullnames |
|----------------|-----------|---------------------|-------------|------------------------|
| 1 | Studio | 2016-09-01 15:30:00 | work, sleep,| John Doe, Martin Smith,|
| | | | work, sleep | John Doe, Martin Smith |
| 2 | Office | 2017-04-02 13:00:00 | sleep | John Doe |
|----------------|-----------|---------------------|-------------|------------------------|
I mean I kinda get that I screwed up my joins but I'm totally stuck at the moment. Any hints? I feel like the solution is simple but I'm totally blind at the moment.
My queue:
SELECT
appointments.id AS 'appointment_id',
room.name AS 'room_name',
appointments.datetime,
GROUP_CONCAT(actions.name SEPARATOR ', ') AS 'actions',
GROUP_CONCAT(users.givenname, ' ', users.surname SEPARATOR ', ') AS 'userfullnames'
FROM appointments
INNER JOIN actions_appointments
ON appointments.id = actions_appointments.appointments_id
INNER JOIN actions
ON actions_appointments.actions_id = actions.id
INNER JOIN users_appointments
ON users_appointments.appointments_id = appointments.id
INNER JOIN users
ON users_appointments.users_id = users.id
INNER JOIN room
ON appointments.room_id = room.id
GROUP BY
appointments.id;
Table structure:
The basic tables:
|-------------------|
| room |
|-------------------|
| id | name |
|--------|----------|
| 1 | Office |
| 2 | Studio |
|-------------------|
|----------------------------------------|
| appointments |
|--------|---------|---------------------|
| id | room_id | datetime |
|--------|---------|---------------------|
| 1 | 2 | 2016-09-01 15:30:00 |
| 2 | 1 | 2017-04-02 13:00:00 |
|--------|---------|---------------------|
|-----------------------------------------|
| users |
|-----------------------------------------|
| id | username | givenname | surname |
|--------|----------|-----------|---------|
| 1 | j.doe | John | Doe |
| 2 | m.smith | Martin | Smith |
|--------|----------|-----------|---------|
|--------------------|
| actions |
|--------------------|
| id | name |
|--------|-----------|
| 1 | work |
| 2 | sleep |
|--------------------|
The intermediate tables:
|------------------------------|
| actions_appointments |
|------------------------------|
| actions_id | appointments_id |
|------------|-----------------|
| 1 | 1 |
| 2 | 1 |
| 2 | 2 |
|------------|-----------------|
|----------------------------|
| users_appointments |
|----------------------------|
| users_id | appointments_id |
|----------|-----------------|
| 1 | 1 |
| 2 | 1 |
| 1 | 2 |
|----------|-----------------|
Edit: The correct queue with DISTINCT
Thanks to Juan.Queiroz and Mike!
SELECT
appointments.id AS 'appointment_id',
room.name AS 'room_name',
appointments.datetime,
GROUP_CONCAT(DISTINCT actions.name SEPARATOR ', ') AS 'actions',
GROUP_CONCAT(DISTINCT users.givenname, ' ', users.surname SEPARATOR ', ') AS 'userfullnames'
FROM appointments
INNER JOIN actions_appointments
ON appointments.id = actions_appointments.appointments_id
INNER JOIN actions
ON actions_appointments.actions_id = actions.id
INNER JOIN users_appointments
ON users_appointments.appointments_id = appointments.id
INNER JOIN users
ON users_appointments.users_id = users.id
INNER JOIN room
ON appointments.room_id = room.id
GROUP BY
appointments.id;
GROUP BY
appointments.id,
room.name,
appointments.datetime