fetching number of records from outer join table - mysql

I have two tables - band and comments. Comments table holds record if any comment has been made on a specific band in the band table. I need number of comments made on a band with all the details from band table. So here is my query
select band.*, count(comments.band) as count from band left join comments on band.id = comments.band
However this query fetches only records that matches both the table. I need all the band table records to be listed even if there is no matching record for it in the comments table (main reason for using left join) Any help?

I think it will work perfectly-
SELECT
band.*, COUNT(comments.band) AS count_no
FROM
band
LEFT JOIN
comments ON band.id = comments.band
GROUP BY band.id;

SQLfiddle:
http://sqlfiddle.com/#!9/986c8/6
SELECT b.name, count(c.band_id) AS comment_count
FROM band AS b
LEFT JOIN comments AS c
ON b.id = c.band_id
GROUP BY b.name;
EDIT: Looks like some people beat me to it!

That query looks correct to me except you don't have a GROUP BY clause. Without a GROUP BY it will only return 1 row with the count for all rows in it. You can use the band tables primary key. ie GROUP BY band.id

Related

php : one to many relationship get the latest row of the many relation table

I have two tables, one is having deposit's (table: deposit) another table is having comments for deposits (table: comment).
Both table are linked by 1 to many relationship ie, one deposit may have many comments.
Below query gives all comments but I want only the last comment (comments table has auto generated id)
SELECT
D.missing_deposit_amount,
D.missing_deposit_date,
C.comment
FROM deposit AS D
LEFT JOIN comments AS C on
C.md_id=D.md_id
WHERE 1
How can i extend this query to give only the last comment corresponding to deposit?
You can search for the last one using a correlated subquery:
SELECT D.missing_deposit_amount, D.missing_deposit_date,
C.comment
FROM deposit D LEFT JOIN
comments C on
ON C.md_id = D.md_id AND
c.id = (SELECT MAX(c2.id) FROM comments c2 WHERE c2.md_id = c.md_id);

How to do SQL Join with many tables (FK tables have looped results sharing ID)

I am newish to SQL and Join statements and I am way out of my league at the moment
I currently have 6 Database Tables that are all linked to the main 7th table based on the main tables ID, however all the information in the other 6 tables are looped and so have several displayed results to the one main tables ID.
Is it possible to join them all into one Join Statement so I can have a results so that everyones information from the main table also shows their information from the 6 other linked tables
So basically when they all have the informationed joined I want to be able to Display all information on a webpage
so I was wondering do I need to do multiple JOIN statements or just one Longer one?
I have Included some Images below that explain it visually. See examples 1 and 2
The columns that are highlighted in yellow are looped to have many results:
2. This is the example of how the information is looped into the
database where there are many Race_id sharing to the same inf_id:
Im not so sure how it will look once it has been joined since some of the information is looped into many Id's and not sure if that means it need to duplicate the column or the rows?? any help would be greatly appreciated.
You could use left join eg for the first tables influencer, social, activities
select i.*, s.follower, s.Social_Medial_URL, a.activity, a.result
from influencer i
left join social s on s.inf_id = i.id
left join activities a on a.inf_id = i.id
you can procede yourself adding the left join for the others tables using the same rules
select i.*
, s.follower_count
, s.social_media_url
, a.compete_activity
, a.compete_results
from influencers i
left join inf_other_social s on s.inf_id = i.id
left join inf_compete_activity a on a.inf_id = i.id
LIMIT 0, 25
I think you are confused about primary key and foreign key. the picture you have given is clearly elaborate everything. as per your db diagram the query might be like this...
select * from
Influencer i
Left Join Social s on i.inf_id = s.inf_id
Left Join Owned_Equip o on i.inf_id=o.inf_id
Left Join Ages_Interacted a on i.inf_id = a.inf_id
Left Join Activities ac on i.inf_id = ac.inf_id
Left Join Awards aw on i.inf_id = aw.inf_id
Left Join History h on i.inf_id = h.inf_id
By using this above query you can get all the information of Influencer and related to him (Social,Owned_Equip,Activities,Award etc) whether they exists or not. If you using only "Join" not "Left Join" then you can only find those records which is common for a single influencer to it's related entities/tables which might you say. as an example: say Influencer (id = 1 , suppose name is dan) after inner join we can get only records related to dan ( his social,owned equipments,activites,awards and so on if those tables contains record related to dan record)

Join all link table entries in one single row

I've been trying to get a query which would allow me to put all music genres of an event (Link table) in a single row but I have been quite unsuccessful so far; it constantly returns 2 rows with the same information about the event in each but changing the music genre entries at the LEFT JOIN. Here's my query:
SELECT
events.*
, music_genres_link.*
FROM events
LEFT JOIN music_genres_link
ON events.id = music_genres_link.event_id
WHERE events.id=1
ORDER BY date DESC
And here's what it returns:
How do I get these two rows together in a single one? I need both the genre_title and genre_id columns.
I'd like to get the whole event row and left join all the music genres found on the link table to the left of the result, as such:
[event result] [music_genre_1 (id, title)] [music_genre_2 (id, title)] etc
I suspect you just want group_concat():
SELECT e.*, GROUP_CONCAT(mgl.genre_title) as genres
FROM events e LEFT JOIN
music_genres_link mgl
ON e.id = mgl.event_id
WHERE e.id = 1
GROUP BY e.id;
This assumes that you want the genre_title only. If you want the genre_id, then you can add another column.
It seems that you have 2 rows that match the join in music_genres_link. You can see that from the two 'gender_id' values - 5 and 295.
Ok now that you have edited your question, you want something that is not typical for SQL. You can achieve that with PIVOT but you dont have limit for the amount of genres and i wouldn't recommend it. You need to rethink your tables and what you want to achieve.

I can't wrap my head around joins

So, alright, I have a few tables. My current query runs against a "historical" table. I want to do a join of some kind to get the most recent status from my Current table. These tables share a like column, called "ID"
Here's the structure
ddCurrent
-ID
-Location
-Status
-Time
ddHistorical
-CID (AI field to keep multiple records per site)
-ID
-Location
-Status
-Time
My goal now is to do a simple join to get all the variables from ddHistorical and the current Status from ddCurrent.
I know that they can be joined on ID since both of them have the same items in their ID tables, I just can't figure out which kind of join is appropriate or why?
I'm sure someone may provide a specific link that goes into great detail explaining, but I'll try to summarize it this way. When writing a query, I try to list the tables from the position of what table do I want to get data from and have that as my first table in the "FROM" clause. Then, do "JOIN" criteria to other tables based on relationships (such as IDs). In your example
FROM
ddHistorical ddH
INNER JOIN ddCurrent ddC
on ddH.ID = ddC.ID
In this case, INNER JOIN (same as JOIN) the ddHistorical table is the left table(listed first for my styling consistency and indentation) and ddCurrent is the right table. Notice my ON criteria that joins them together is also left alias.column = right alias table.column -- again, this is just for mental correlation purposes.
an Inner Join (or JOIN) means a record MUST have a match on each side, otherwise it is discarded.
A LEFT JOIN means give me all records in the LEFT table (ddHistorical in this case), regardless of a matching in the right-side table (ddCurrent). Not practical in this example.
A RIGHT JOIN is the reverse... give me all records from the RIGHT-side table REGARDLESS of a matching record in the left side table. Most of the time you will see LEFT-JOINs more frequently than RIGHT-JOINs.
Now, a sample to mentally get the left-join. You work at a car dealership and have a master table of 10 cars that are sold. For a given month, you want to know what IS NOT selling. So, start with the master table of all cars and look at the sales table for what DID sell. If there is NO such sales activity the right-side table will have NULL value
select
M.CarID,
M.CarModel
from
MasterCarsList M
LEFT JOIN CarSales CS
on M.CarID = CS.CarID
AND month( CS.DateSold ) = 4
where
CS.CarID IS NULL
So, my LEFT join is based on a matching car ID -- AND -- the month of sales activity is 4 (April) as I may not care about sales for Jan-Mar -- but would also qualify year too, but this is a simple sample.
If there is no record in the Car Sales table it will have a NULL value for all columns. I just happen to care about the car ID column since that was the join basis. That is why I am including that in the WHERE clause. For all other types of cars that DO have a sale it will have a value.
This is a common approach you will see in querying where someone looking for all regardless of other... Some use a where NOT EXIST ( subselect ), but those perform slower because they test on every record. Having joins is much faster.
Other examples may be you want a list of all employees of a company, and if they had some certification / training to show it... You still want all employees, but LEFT-JOINING to some certification/training table would expose those extra field as needed.
select
Emp.FullName,
Cert.DateCertified
FROM
Employees Emp
Left Join Certifications Cert
on Emp.EmpID = Cert.EmpID
Hopefully these samples help you understand better the relationship for queries, and now to actually provide answer for your needs.
If what you want is a list of all "Current" items and want to look at their historical past, I would use current FIRST. This might be if your current table of things is 50, but historically your table had 420 items. You don't care about the other 360 items, just those that are current and the history of those.
select
ddC.WhateverColumns,
ddH.WhateverHistoricalColumns
from
ddCurrent ddC
JOIN ddHistorical ddH
on ddC.ID = ddH.ID
If there is always a current field then a simple INNER JOIN will do it
SELECT a.CID, a.ID, a.Location, a.Status, a.Time, b.Status
FROM ddHistorical a
INNER JOIN ddCurrent b
ON a.ID = b.ID
An INNER JOIN will omit any ddHistorical rows that don't have a corresponding ID in ddCurrent.
A LEFT JOIN will include all ddHistorical rows, even if they don't have a corresponding ID in ddCurrent, but the ddCurrent values will be null (because they're unknown).
Also note that a LEFT JOIN is just a specific type of outer join. Don't bother with the others yet - 90% or more of what you'll ever do will be INNER or LEFT.
To include only those ddHistorical rows where the ID is in ddCurrent:
SELECT h.CID, h.ID, h.Location, h.Status, c.Status, h.Time
FROM ddHistorical h
INNER JOIN ddCurrent c ON h.ID = c.ID
If you want to include ddHistorical rows even if the ID isn't in ddCurrent:
SELECT h.CID, h.ID, h.Location, h.Status, c.Status, h.Time
FROM ddHistorical h
LEFT JOIN ddCurrent c ON h.ID = c.ID
If all ddHistorical rows happen to match an ID in ddCurrent, note that both queries will return the same result.

How to properly join on a column in MYSQL which potentially has no matching results?

Not sure if my title explains it very well so here's an example. I have two MYSQL tables, comments and votes_comments which are matched based on a field comment_id. For sample data comments has two rows and votes_comments has one row which matches one of the comments row. AKA Two comments were written and a single person voted on one of them Given that, the following query returns 2 rows:
SELECT comments.*, users.username FROM comments
JOIN users ON users.user_id = comments.user_id
WHERE comments.track_id=6 AND comments.parent_id=-1
GROUP BY comments.comment_id
Now what I want to do is join on votes_comments which may or may not have a matching row. What I want to do is grab the matching value if it exists or return null in the column if there is no matching result. AKA: Did the user vote it up, down or not at all (null). Here is my modified query:
SELECT comments.*, users.username, votes_comments.vote FROM comments
JOIN users ON users.user_id = comments.user_id
LEFT JOIN votes_comments ON votes_comments.comment_id = comments.comment_id
WHERE track_id=6 AND parent_id=-1 AND votes_comments.user_id=1
GROUP BY comments.comment_id
This query only returns one row since I only have a single row in votes_comments. I thought that left join would return results the way I want but apparently not. Any ideas how to get what I'm looking for?
I suspect the WHERE clause AND votes_comments.user_id=1 is causing the problem.
Read a tutorial on Joins and you'll see that the result of your LEFT JOIN is a temporary table with two rows, and for each row, fields from comments JOIN users and from votes_comments. If no matching record from votes_comments exists, the fields in the temporary table are filled with NULL values.
Your WHERE clause, AND votes_comments.user_id=1, will fail because votes_comments.user_id is NULL in the rows of user with no matching votes_comments record.
If what you actually want is to join to the row in votes_comments what matches a specific user ID (e.g. ID=1), then your ON clause should be something like
ON votes_comments.comment_id = comments.comment_id
AND votes_comments.user_id=1
If you want to have rows from both of the tables you might consider using FULL OUTER JOIN. Like this:
SELECT comments.*, users.username, votes_comments.vote FROM comments
JOIN users ON users.user_id = comments.user_id
FULL OUTER JOIN votes_comments ON votes_comments.comment_id = comments.comment_id
AND votes_comments.user_id=1
WHERE track_id=6 AND parent_id=-1
GROUP BY comments.comment_id
Edit
Sorry about that. You can sumulate a FULL OUTER JOIN read more about it here and here