left join with condition in MySQL - mysql

I do have 2 tables students and attendance.
Students
student_id name
---------- -----
1 | A
2 | B
3 | C
Attendance
id | date | student_id
------------------------------
1 | 2015-12-05 | 1
2 | 2015-12-05 | 2
3 | 2015-12-05 | 3
4 | 2015-12-06 | 2
5 | 2015-12-06 | 3
I need the details of students who are absent on 2015-12-06.
The result should be : 1 | A
I know the query I am trying is wrong but it should be something like :
SELECT *
FROM students s
left join attendance a on s.id=a.student_id
where date='2015-12-06' and a.id IS NULL
Please suggest me.

I guess this should work:
SELECT * FROM Students
WHERE student_id NOT IN
(SELECT s.student_id
FROM Students s
LEFT JOIN Attendance a
ON s.student_id = a.student_id
WHERE a.date LIKE '2015-12-06'
GROUP BY s.student_id);
Not tested, but i belive you got the idea
//NOTE: I guess you can get rid of the GROUP BY s.student_idpart

Related

How can I not take in consideration values join without record on the db

I'm in front of a "minor" problem taht looks easy but I didn't suceed to resolve it.
I have three tables in my Database :
Table gp
____________
id | name |
____________
1 | Le Mans|
2 | Toulon |
3 | Rennes |
Table player
____________
id | name |
____________
1 | Thibaut|
2 | Fred |
3 | Samir |
Table Records
_____________________________
id | gp_id | player_id | time
_____________________________
1 | 1 | 1 | 17860
2 | 2 | 1 | 11311
3 | 3 | 1 | 33133
4 | 3 | 2 | 11113
5 | 2 | 2 | 44444
6 | 1 | 2 | 13131
7 | 1 | 3 | 11111
8 | 3 | 3 | 21112
I want to get a sum of time for players that have a record on every gp ( so in my case, just players Thibaut and Fred have a record on the 3 gp ( Samir has just a record on two gp ) ).
I have no idea how I can get that, of course this SQL query is retrieving a sum but from this query I want to escape the guys that don't have a record on every GPs, but I'm blocked at that point ...
SELECT p.name, sum(time)
from records r
join gp g on r.gp_id = g.id
join player p on r.player_id = p.id
group by r.player_id
Thanks in advance guys !
You could use having count to exclude the records that don't have a record on every GPs.
Try:
select p.name,
sum(`time`) as tot_sum
from records r
inner join player p on r.player_id=p.id
inner join gp g on g.id=r.gp_id
group by p.name
having count(distinct gp_id) = (select count(distinct id) from gp)
https://dbfiddle.uk/t8QwSFDY
having count(distinct gp_id) = (select count(distinct id) from gp) will match only the records in the record table that have a record on every gp.

Join Table B to Table A only if entry in Table B equals entry in Table C

I have 3 tables. clients, sales and potential_sales.
The basic structure is as follows:
Clients Table:
+-----------+-------+----------------+
| client_id | name | address |
+-----------+-------+----------------+
| 1 | john | 12 blue ave |
| 2 | paul | 34 green lane |
| 3 | peter | 69 yellow road |
+-----------+-------+----------------+
Potential Sales Table:
+----------+------------+---------------------+
|product_id | client_id | received_free_promo |
+-----------+------------+---------------------+
| 3 | 1 | 1 |
| 4 | 2 | 0 |
| 5 | 2 | 1 |
+-----------+------------+---------------------+
Sales:
+----------+-----------+-----------+
| sales_id | client_id | product_id |
+----------+-----------+------------+
| 1 | 2 | 4 |
| 2 | 43 | 4 |
| 3 | 2 | 5 |
| 4 | 18 | 93 |
+----------+-----------+------------+
I want to join clients and potential_sales tables ONLY IF
1) received_promo equals 1 AND
2) they actually bought the promo package (i.e. the product_id for the potential sale has an entry into the sales table ). If they didn't eventually buy the free_promo product then I do not want to join the clients and potential_sales table at all. This is important - I can't simply JOIN to figure it out because this is only a small part of a bigger query and I can't afford to JOIN for no reason.
(Here is how I would like it to work. It's mainly pseudo-code to describe what I want to happen)
SELECT
c.*
FROM
clients c
LEFT JOIN potential_sales ps ON ps.client_id=c.id
LEFT JOIN sales ps ON s.product_id=ps.product_id
IF(s.sales_id) JOIN potential_sales ps ON ps.client_id=c.id
How do I do this in MySQL? I haven't come close to a solution. Please help!
Try this:
SELECT A.*, B.product_id, B.received_free_promo
FROM Clients A JOIN
(SELECT * FROM PotentialSales
WHERE received_free_promo=1) B
ON A.client_id=B.client_id
WHERE EXISTS (SELECT 1 FROM Sales C
WHERE A.client_id=C.client_id
AND B.product_id=C.product_id);
See Demo on SQL Fiddle.
What you are missing is the EXISTS clause:
SELECT
C.*,
P.*
FROM
Clients AS C
INNER JOIN PotentialSales AS P ON C.client_id = P.client_id
WHERE
P.received_free_promo = 1 AND
EXISTS (
SELECT
'the client already sold that product'
FROM
Sales AS S
WHERE
S.client_id = C.client_id AND
S.product_id = P.product_id)
Try this..." select * from client as c natural join potential as p join sales as s on p.product_id = s.product_id where received_promo = 1". select * will mention everything from all the 3 tables. You can choose what you want as the result.

MySQL join tables where all left records are in right

I need to get matching records from table A that are also in table B. But I can't figure out if I can do this in just one query.
Table A
id | order_id | title
----------------------------------
1 | 1114 | Product 1
2 | 1115 | Product 1
3 | 1115 | Product 2
4 | 1116 | Product 1
5 | 1117 | Product 3
6 | 1118 | Product 4
7 | 1118 | Product 5
Table B
id | order_id | a_id | title
----------------------------------
1 | 2221 | 1 | Product 1
2 | 2222 | 2 | Product 1
3 | 2222 | 3 | Product 2
4 | 2223 | 7 | Product 5
Now I need all order_id values from table A where all products are also in table B. So this would result in:
1114
1115
1116 fails because there is no b.a_id value 4
1117 fails because there is no b.a_id value 5
1118 fails because not both 6 AND 7 are in b.a_id
I tried an INNER JOIN, but this would also return 1118. I also tried a LEFT JOIN with WHERE b.a_id IS NULL, but that is the exact opposite. So I tried a RIGHT JOIN, but that also returns 1118.
See this SQL Fiddle.
I hope I made clear what my goal is and I'm curious if this could be managed by one query.
It's not perfect, but it does return the correct results for your existing data through the SQL Fiddle. Maybe you can use this as a starting point?
SELECT a.order_id, count(distinct a.id) as aCount, count(distinct b.a_id) as bCount
FROM a
LEFT JOIN b ON a.id = b.a_id
GROUP BY a.order_id
HAVING aCount = bCount;
It is doable in a single query:
SELECT a.order_id, COUNT(a.id) as cntA, COUNT(b.id) AS cntB
FROM a
LEFT JOIN b ON a.id = b.a_id
GROUP BY a.order_id
HAVING cntA = cntB;

How to write this basic sql statement

So I have 4 tables that are connected via foreign keys namely result, position, student, candidates
What i need to achieve is this:
output:
------------------------
s_fname | count(c_id)
-----------------------
Mark | 2 -> President
France| 2 -> President
.. to count as to how many times a c_id have been repeated in the table "result" which is also filtered by pos_id from the "candidates" table
Below is my code which lacks the counting part:
select s_fname
from results, candidates, student, positioning
where results.c_id = candidates.c_id
AND student.sid = results.sid
AND candidates.pos_id = positioning.pos_id
AND positioning.pos_id = 1
Group BY results.sid;
..which I know lacks a lot of things ...
Thanks
it seems very complex to me but i know there are gurus here who can achieve this,
result table
---------------------
| r_id | sid | c_id |
---------------------
1 | 1 | 1
2 | 1 | 2
3 | 1 | 4
4 | 2 | 1
5 | 2 | 2
6 | 2 | 4
7 | 3 | 3
8 | 3 | 2
9 | 5 | 3
10 | 5 | 2
----------------------
student table
----------------
| s_id| s_fname|
----------------
1 | Mark
2 | Jorge
3 | France
4 | James
--------------------
Candidates Table
------------------------
| c_id | sid | pos_id
------------------------
1 | 1 | 1
2 | 2 | 2
3 | 4 | 3
4 | 3 | 1
5 | 5 | 2
----------------------
positioning Table
-----------------------
| pos_id | po_name |
-----------------------
1 | President
2 | Vice President
3 | Secretary
4 | Treasurer
This is untested, but should return your intended result.
What it does is joins all of your tables on the related foreign keys, effectively giving a wide table of all of your columns. Then we limit on the candidates that are running for the President position. Since we need to group because of the count aggregate we group on the name. The count should reflect the number of votes they got, because there is a one to many relationship to the result table.
SELECT s_fname, Count(*)
FROM studentTable st
INNER JOIN Candidates c On c.sid = st.s_ID
INNER JOIN positioning p on c.pos_ID = p.pos_ID
INNER JOIN results r on st.s_ID = r.s_ID
WHERE po_Name = "President"
GROUP BY s_Fname
Due to a misunderstanding of the intended joins, the following query should show the appropriate results.
SELECT s_fname, Count(*)
FROM studentTable st
INNER JOIN Candidates c On c.sid = st.s_ID
INNER JOIN positioning p on c.pos_ID = p.pos_ID
INNER JOIN results r on c.c_ID = r.c_ID
WHERE po_Name = "President"
GROUP BY s_Fname
Code:
SELECT s_fname AS [Student Name], COUNT(A.c_id) AS [Count], po_name AS [Position]
FROM results AS A INNER JOIN candidates AS B ON A.c_id=B.c_id
INNER JOIN student AS C ON A.sid=C.sid
INNER JOIN positioning AS D ON B.pos_id=D.pos_id
WHERE B.pos_id = 1
GROUP BY s_fname
SELECT s.s_fname, COUNT(*), p.po_name
FROM students s
JOIN candidates c ON c.s_id = s.s_id
JOIN positioning p ON c.pos_id = p.pos_id
JOIN results r ON s.s_id = r.s_id
WHERE p.pos_id = 1
GROUP BY s.s_id
http://sqlfiddle.com/#!2/9472a/17

How do I put a conditioned count of a joined table in a separate column of the same joined table

Lets say, I have two tables - people and bonus
------------
people
------------
people_id | company_id | job_id
1 | 1 | 2
2 | 1 | 4
3 | 2 | 1
4 | 2 | 3
5 | 3 | 5
------------
bonus
------------
job_id | bonus_id
1 | 101
2 | 102
3 | 103
Now, I want to have a joined table like the following
-------------
JOINED TABLE
-------------
people_id | company_id | job_id | bonus_id | no_of_bonus_for_company
1 | 1 | 2 | 102 | 1
2 | 1 | 4 | NULL | 1
3 | 2 | 1 | 101 | 2
4 | 2 | 3 | 103 | 2
5 | 3 | 5 | NULL | 0
I need to have the main search term in people_id as in -
SELECT p.people_id,
p.company_id,
p.job_id,
b.bonus_id
FROM people p
LEFT JOIN bonus b
ON p.job_id = b.job_id
WHERE p.people_id IN (1,2,3,4,5)
ORDER BY p.people_id ASC;
But how do I get the fifth column of the joined table? It actually counts the no. of bonus id's for each company id in the joined table itself.
I can only assume that you are telling us part of the picture so I will reserve judgement about the DB schema, normalization etc.
Given the presented facts you can retrieve the information in the following manner.
NOTE : This is TSQL syntax but I don't think that the mySQL syntax should be very different i.e. ISNULL -> IFNULL
SELECT p.people_id
, p.company_id
, p.job_id
, b.bonus_id
, ISNULL((
SELECT COUNT(pt.Job_Id)
FROM Bonus bt
INNER JOIN People pt
ON pt.job_Id = bt.job_Id
WHERE pt.company_Id = p.company_Id
GROUP BY pt.company_Id
), 0) AS no_of_bonus_for_company
FROM People p
LEFT JOIN Bonus b
ON p.job_Id = b.job_Id