MySQL count number of occurrences of field value with join data - mysql

I have 2 tables in my database, see below:
Events Table
title | venue_id
event 1 | 1
event 2 | 1
event 3 | 1
event 4 | 1
event 5 | 2
event 6 | 2
event 7 | 2
event 8 | 2
event 9 | 3
event 10 | 3
Venues Table
id | title
1 | Venue 1
2 | Venue 2
3 | Venue 3
The desired results I am looking for would be
venue_title | event_count
Venue 1 | 4
Venue 2 | 4
Venue 3 | 2
I have been trying to do this with joins but for some reason I am getting the count 1 back for every venue.
This is what my SQL looks like just now.
SELECT
count(DISTINCT events.venue_id),
venues.title,
FROM
events
INNER JOIN
venues
ON venues.id = events.venue_id
I have looked around various over SO posts but unable to find anything that has been able to help. I am really a beginner at SQL like this.
Thanks

You're missing the group by clause:
SELECT
count(DISTINCT events.venue_id),
venues.title,
FROM
events
INNER JOIN
venues
ON venues.id = events.venue_id
GROUP BY -- Here!
venues.id, venutes.title

You can do a group by on events table, get the results and do an inner join of this obtained result with venues table. This can also improve performance of inner join since it will have to map fewer number of rows.
SQL:
select v.title,derived.event_count
from venues v
inner join (select venue_id,count(venue_id) as event_count
from events
group by venue_id) derived
on v.id = derived.venue_id

you can also use GROUP BY and HAVING clause
SELECT
count(events.venue_id),venues.title,
FROM events
INNER JOIN venues
ON venues.id = events.venue_id group by events.venue_id having count(events.venue_id) > 0
The GROUP BY Clause is used to group rows with same values and HAVING clause is used to restrict the results returned by the GROUP BY clause.
so > 0 return the duplicate values having count > 0

Related

MySQL gruop by when there is no aggregation

I have a table called booking_details.
id | tour_id | tour_fee| booking_id
1 | 1 | 200 | 1
2 | 2 | 350 | 1
3 | 1 | 200 | 2
4 | 2 | 350 | 3
tour_id refers to the Tours table and the booking_id refers Bookings table.
I want to get a report like this
tour_id 1 refers to New york tour
tour_id 2 refers to Paris tour
I need a generate a report something like this
tour name | total_income | number_of_bookings
New york tour| 400 | 2
Paris tour | 700 | 2
Here basicaly tour name, total income from that tour and number of bookings for that tour.
What I have done upto now is this. But this gives me a syntax error. It seems I can't group by results.
SELECT booking_details.*,Tours.name as name, count(Tours.id) FROM booking_details
inner join Tours on
booking_details.tour_id = Tours.id group by Tours.name;
How do I achive this using MySQL?
you have used aggregation count() in your query and from your requirement, it shows you need aggregation. when you used aggregation you have to put selection column in group by also
SELECT Tours.name as name,sum(tour_fee) income, count(Tours.id)
FROM booking_details
inner join Tours on
booking_details.tour_id = Tours.id group by Tours.name
As you used in selection booking_details.* which means every column of booking table but you have not put those column in group by so it thrown error
You are trying to select non aggregated columns which are not part of your GROUP BY clause.
Change your query like following.
SELECT t.NAME AS NAME,
Sum(bd.tour_fee) total_income,
Count(t.id) number_of_bookings
FROM booking_details bd
INNER JOIN tours t
ON bd.tour_id = t.id
GROUP BY t.NAME;
Small suggestion, as a good practice you should use alias names for tables when joining.
You need to add all other columns in group by except aggregated fields
SELECT
booking_details.tour_id,
Tours.name AS name,
SUM(tourfee) AS total_income,
COUNT(Tours.id)
FROM
booking_details
INNER JOIN
Tours ON booking_details.tour_id = Tours.id
GROUP BY
booking_details.tour_id, Tours.name

Find duplicates from same table and constraint them from another table in sql

Oh, my title is not the best one and as English is not my main language maybe someone can fix that instead of downvoting if they've understood the issue here.
Basically i have two tables - tourneyplayers and results. Tourneyplayers is like a side table which gathers together tournament information across multiple tables - results, tournaments, players etc. I want to check duplicates from the results table over column day1_best, from single tournament and return all the tourneyplayers who have duplicates.
Tourneyplayers contain rows:
Tourneyplayers
tp_id | resultid | tourneyid
1 | 2 | 91
2 | 21 | 91
3 | 29 | 91
4 | 1 | 91
5 | 3 | 92
Results contains rows:
Results:
r_id | day1_best
1 | 3
2 | 1
3 | 4
.. | ..
21 | 1
.. | ..
29 | 2
Now tourney with id = 91 has in total 4 results, with id's 1,2,21 and 29. I want to return values which have duplicates, so currently the result would be
Result
tp_id | resultid | day1_best
1 | 2 | 1
2 | 21 | 1
I tried writing something like this:
SELECT *
FROM tourneyplayers
WHERE resultid
IN (
SELECT r1.r_id
FROM results AS r1
INNER JOIN results AS r2 ON ( r1.day1_best = r2.day1_best )
AND (
r1.r_id <> r2.r_id
)
)
AND tourneyid =91
But in addition to values which had the same day1_best it chose two more which did not have the same. How could i improve my SQL or rewrite it?
First you JOIN both tables, so you know how the data looks like.
SELECT *
FROM tourney_players t
JOIN results r
ON t.`resultid` = r.`r_id`;
Then using the same query you GROUP to see what tourneyid, day1_best combination has multiple rows
SELECT `tourneyid`, `day1_best`, count(*) as total
FROM tourney_players t
JOIN results r
ON t.`resultid` = r.`r_id`
GROUP BY `tourneyid`, `day1_best`;
Finally you use the base JOIN and perform a LEFT JOIN to see what rows has a match and show only those rows.
SELECT t.`tp_id`, r.`r_id`, r.`day1_best`
FROM tourney_players t
JOIN results r
ON t.`resultid` = r.`r_id`
LEFT JOIN (SELECT `tourneyid`, `day1_best`, count(*) as total
FROM tourney_players t
JOIN results r
ON t.`resultid` = r.`r_id`
GROUP BY `tourneyid`, `day1_best`
HAVING count(*) > 1) as filter
ON t.`tourneyid` = filter.`tourneyid`
AND r.`day1_best` = filter.`day1_best`
WHERE filter.`tourneyid` IS NOT NULL;
SQL DEMO
OUTPUT
Please try this :
Select tp.tp_id , tp.resultid ,r.day1_best from (Select * from Tourneyplayers
where tourneyid = 91)as tp inner join (select * from Result day1_best in(select
day1_best from result group by day1_best having count(*)>1 ) )as r on tp.resultid
= r.r_id ;

mysql using limit in a left join not working properly

I have two tables looking like this
Patient (table 1)
id | name
------------
1 | robel
2 | dave
Patient_followup (table 2)
id | Patient_id | date_created
-----------------------
1 | ---- 1 -- | 01/01/2015
2 | -----1 -- | 01/07/2016
I want to display all the patients with their perspective latest followup data. so i tried using this query
Select * from patient
left join Patient_followup pf on pf.Patient_id = patient.id
order by pf.date_created
Limit 1
but this is giving me only the first patient robel. i tryed removing the limit and its giving me two records of robel and one record of dave because robel has two followup data. so what should i do to get only one record of each patient ?
Try this:
Select
*
from
patient
left join
(SELECT
id as pf_id,
MAX(date_created) as latest_followup_date,
Patient_id
FROM
Patient_followup
GROUP BY
Patient_id) as pf
ON pf.Patient_id = patient.id
As mentioned by anton in the first comment, you need to use aggregation to get one record per patient.
Select patient.*,MAX(pf.date_created) as followupdate,group_concat(pf.date_created) from patient
left join Patient_followup pf on pf.Patient_id = p.patient.id
group by patient.id
order by pf.date_created
Here, you will get your values comma separated.
1) "Limit 1" will only return the first result. Typically this is used if the query will result in a very large result set and you only want the first few results.
Ex:
"LIMIT 30" will show the first 30 rows of the query.
2) I would change to setup of the tables so the query is smoother. Right now, you create a new line for each follow-up date even if the patient is already created. You could add another column in the table named "FollowUpDate". That way each patient record has the table id, patient id, creation date and followup date in the same row. That way, each patient has only one row.
EX:
Patient (table 1)
id | name | created_date | next_followup_date |
1 | Robel | 01/01/2015 | 01/01/2016 |
2 | Dave |[created_date]| [next_follup_date] |
Patient_followup (table 2)
id | Patient_id | date_created | followUpDate |
1 | 1 | 01/01/2015 | 06/01/2016 | // example date
2 | 1 | 01/01/2015 | 01/01/2016 |
3 | 2 |[date created]| [FollowUpDate] |
3) Change query to:
Use this select statement to get all patient records.
Select * from patient
left join Patient_followup pf on pf.Patient_id = patient.id
order by pf.Patient_id
Use this select statement to get the specific patient record information.
Select * from patient
inner join Patient_followup pf on pf.Patient_id = patient.id
where patient.id = 1 //to get robel. Edit this line as necessary, perhaps by user input...
order by pf.followUpDate
NOTE: When you insert a new record in Patient_followup, make sure you update Patient.next_followup_date.
I hope this helps!

How can I join these MYSQL tables?

I'm having 2 tables. Table A contains a list of people who booked for an event, table B has a list of people the booker from table A brings with him/her. Both tables have many colums with unique data that I need to do certain calculations on in PHP , and as of now I do so by doing queries on the tables with a recursive PHP function to resolve it. I want to simplify the PHP and reduce the amount of queries that come from this recursive function by doing better MYSQL queries but I'm kind of stuck.
Because the table has way to many columns I will give an Excerpt of table A instead:
booking_id | A_customer | A_insurance
1 | 134 | 4
Excerpt of table B:
id | booking_id | B_insurance
1 | 1 | 0
2 | 1 | 1
3 | 1 | 1
4 | 1 | 3
The booking_id in table A is unique and set to auto increment, the booking_id in table b can occur many times (depending on how many guests the client from table A brings with him). Lets say I want to know every selected insurance from customer 134 and his guests, then I want the output like this:
booking_id | insurance
1 | 4
1 | 0
1 | 1
1 | 1
1 | 3
I have tried a couple of joins and this is the closest I've came yet, unfortunately this fails to show the row from A and only shows the matching rows in B.
SELECT a.booking_id,a.A_customer,a.A_insurance,b.booking_id,b.insurance FROM b INNER JOIN a ON (b.booking_id = a.booking_id) WHERE a.booking_id = 134
Can someone point me into the right direction ?
Please note: I have altered the table and column names for stackoverflow so it's easy for you guys to read, so it's possible that there is a typo that would break the query in it right now.
I think you need a union all for this:
select a.booking_id, a.insurance
from a
where a.a_customer = 134
union all
select b.booking_id, b.insurance
from a join
b
on a.booking_id = b.booking_id
where a.a_customer = 134;
The simplest way I can think of to achieve this is to use a UNION:
SELECT booking_id, A_insurance insurance
FROM A
WHERE booking_id = 134
UNION
SELECT booking_id, B_insurance insurance
FROM B
WHERE booking_id = 134
As my understanging of your isso is right, that should give you the result you need:
SELECT a.booking_id,a.insurance FROM a WHERE a.booking_id = 134
union
SELECT a.booking_id,b.insurance FROM b INNER JOIN a ON (b.booking_id = a.booking_id) WHERE a.booking_id = 134

mysql left join produces fewer results than expected

There are a number of left join questions already, but still I can't quite put my finger on this issue. The WHERE condition doesn't look sensible to move.
The problem is that there should be 4 rows returned but only 1 is.
In checking the left join conditions, there is 1 row returned for each left join, which is correct for the number of records in the table, however the query below returns 1 record instead of 4, but I can't see how to return 4, yet.
Query follows: (Gives 1 result not 4; 4 being expected)
SELECT
list.uid,
list.business_uid,
list.creator_name,
business.company_name,
list_alias.uid AS list_alias_uid,
list_alias.alias AS list_alias,
list_member.uid AS list_member_uid,
mailbox.full_name AS list_member_name,
mailbox.email_address AS list_member_email_address
FROM
mailbox,
business,
list
LEFT JOIN
list_alias ON list_alias.list_uid=list.uid
LEFT JOIN
list_member ON list_member.list_uid=list.uid
WHERE
list.business_uid='1'
AND list.business_uid=business.uid
AND mailbox.uid=list_member.mailbox_uid
ORDER BY
list.full_name ASC
Data:
Business UID 1 has 4 lists
SELECT * FROM list WHERE business_uid=1 -- gives 4 results
SELECT * FROM list_alias WHERE list_uid IN (SELECT uid FROM list WHERE business_uid=1) -- gives 1 result
SELECT * FROM list_member WHERE list_uid IN (SELECT uid FROM list WHERE business_uid=1) -- gives 1 result
Any pointers on what I could check would be welcome.
Table Sample Data:
list:
uid | business_uid | creator_name | full_name
--------------------------------------------------
1 1 List Maker Subscribe to W
2 1 List Maker Subscribe to X
3 1 List Maker Subscribe to Y
4 1 List Maker Subscribe to Z
business:
uid | company_name
-------------------
1 List Company
list_alias:
uid | list_uid | alias
----------------------------------------
1 1 subscriber#list-url.com
list_member:
uid | list_uid | mailbox_uid
------------------------------------
1 1 1
mailbox:
uid | full_name | email_address
-------------------------------
1 I am He me#me.com
Try this using a single join methodology, like so.
SELECT list.uid,
list.business_uid,
list.creator_name,
b.company_name,
la.uid AS list_alias_uid,
la.alias AS list_alias,
lm.uid AS list_member_uid,
m.full_name AS list_member_name,
m.email_address AS list_member_email_address
FROM list LEFT JOIN list_member lm ON lm.list_uid=list.uid
LEFT JOIN mailbox m ON m.uid=lm.mailbox_uid
LEFT JOIN business b ON list.business_uid=b.uid
LEFT JOIN list_alias la ON la.list_uid=list.uid
WHERE list.business_uid=1
ORDER BY list.full_name ASC
Question: What are the values of 'uid' from the 'list' table? Because 'uid' is not the same as 'business_uid'. What I mean is ...
If the 'list' table has this ...
'uid' 'business_uid'
1 1
2 1
3 1
4 1
Then that is the problem. You are returning the same 'busines_uid' but a different 'uid' which means it will only match the first record.