MYSQL one to many JOIN - sql

I have this query and I need to include another join on a table called "likes" where updates.id = likes.update_id. There will be 0 or more matches on this join.
"SELECT * FROM users
INNER JOIN updates ON users.remote_id=updates.owner_id
ORDER BY updates.status_time DESC LIMIT 50"
This is probably fairly simple, but I haven't been able to find any examples for this kind of query.
The situation is basically that I'm displaying a list of items. I do a join on the users table to grab the user who created each item. I also need to do a join on the "likes" tables to display the 0+ people who liked each item.
EDIT: My Solution
Ok, here's the successful join and combining of duplicate results (due to the fact that there are multiple "likes" for each update) using GROUP_CONCAT.
"SELECT users.*,updates.update_id,updates.content,updates.status_time,
GROUP_CONCAT(likes.liker SEPARATOR ',') AS liked_by
FROM updates
LEFT OUTER JOIN likes ON updates.update_id = likes.update_id
JOIN users ON users.remote_id = updates.owner_id
GROUP BY updates.update_id
ORDER BY updates.status_time DESC
LIMIT 200"

SELECT * FROM users
LEFT OUTER JOIN updates ON users.remote_id=updates.owner_id
INNER JOIN likes ON <join condition here>
ORDER BY updates.time DESC LIMIT 50
Will that work?
If not, can you clarify what exactly your question is? Does the query you have not work?

if you have a 1 to n relation the you should use a LEFT JOIN , i mean if there's only 1 user and many likes.user_id you should doit with the following way
"SELECT * FROM users LEFT JOIN updates ON (users.remote_id=updates.owner_id) ORDER BY updates.time DESC LIMIT 50"
this way you'd get all the updates from a certain user :)
cheers

Related

Access SQL Select value with more rows many to many relationship

I'm using Access for a cookbook database, an excercise for Uni.
I'm trying to make a query for a many-to-many relationship.
I have ricette and ingredienti tables, and a junction table named ricetta_ingrediente. Now I should make a query that retrieves each ricette associated with ingredienti used.
EDIT: Part of the question got deleted, I need to retrieve the recipe's ingredients of the one with the most ingredients used, it's the result I have to obtain.
Every single try got me either a syntax error or an empty result - how can I achieve this query?
MORE INFOS
The relationship schema
[
I've tried to implement this suggestion, failing at it, how should it be?
Also here's my try and Access error :
[
Use the query builder DesignView to assist in building SQL statement. Result should look like:
SELECT ricette.nome, ingredienti.nome
FROM ingredienti
RIGHT JOIN (ricette RIGHT JOIN ricetta_ingrediente
ON ricette.ID = ricetta_ingrediente.id_ricetta)
ON ingredienti.ID = ricetta_ingrediente.id_ingrediente;
To retrieve recipe with the most ingredients as well as the ingredients, like:
SELECT TOP 1 ricette.nome, ingredienti.nome
FROM (SELECT id_ricetta, Count([id_ingrediente]) AS CountIng
FROM ricetta_ingrediente GROUP BY id_ricetta) AS Q1
RIGHT JOIN (ricette RIGHT JOIN (ingredienti RIGHT JOIN ricetta_ingrediente
ON ingredienti.ID = ricetta_ingrediente.id_ingrediente)
ON ricette.ID = ricetta_ingrediente.id_ricetta)
ON Q1.id_ricetta = ricetta_ingrediente.id_ricetta
ORDER BY Q1.CountIng DESC;
This will not resolve ties. All recipes with the number of ingredients matching the TOP 1 count will return. How should the query know you want only 1 and which one?
Your query is fine. You just need parentheses, because this is MS Access.
I would also use table aliases:
SELECT r.nome, i.nome
FROM (ricette as r INNER JOIN
ricetta_ingrediente as ri
ON r.ID = ri.id_ricetta
) INNER JOIN
ingredienti as i
ON i.ID = ri.id_ingrediente;
EDIT:
For the revised question:
SELECT TOP (1) r.nome
FROM (ricette as r INNER JOIN
ricetta_ingrediente as ri
ON r.ID = ri.id_ricetta
) INNER JOIN
ingredienti as i
ON i.ID = ri.id_ingrediente
GROUP BY r.nome
ORDER BY COUNT(*) DESC;

SQL - Conditional Left Join Count Performance is Slow

I am using SQL Server 2012.
I have three tables. Builders, Addresses and BuilderAddresses.
I have the following query which is used to give me my total count of records during paging:
SELECT COUNT(*) FROM Builders
LEFT JOIN Addresses ON Addresses.AddressId IN
(SELECT AddressId FROM BuilderAddresses WHERE BuilderId = Builders.BuilderId AND IsPrimary = 1)
WHERE Builders.[Email] LIKE '%TEST'%
ORDER BY Builders.[Name]
This query is particularly slow when records in the table approach 100k+. Does any one have any suggestions on how to get this query to execute faster??
On a table with 120K records, it take 452ms to get the count. When it comes to returning the records used in the paging, say 100 rows, it takes 11ms. I would really like to improve this if I can.
If I need to add greater detail, please let me know and I will edit the question.
The ORDER BY is not necessary for the COUNT, and you can remove that IN validation by joining with BuilderAdresses directly.
Try something like this:
SELECT COUNT(*)
FROM Builders b
LEFT JOIN BuilderAddresses ba ON ba.BuilderId = b.BuilderId AND isPrimary = 1
LEFT JOIN Addresses a ON a.AddressId = ba.AddressId
WHERE Builders.[Email] LIKE '%TEST' %
The problem is most likely to be with using IN as part of the join predicate. What it looks like you need to do is first join the junction table BuilderAddresses and then join Addresses, so something like this
SELECT COUNT(*) FROM Builders
JOIN BuilderAddresses ON BuilderAddresses.BuilderId = Builders.BuilderId AND isPrimary = 1
JOIN Addresses ON Addresses.AddressId = BuilderAddresses.AddressId
WHERE Builders.[Email] LIKE '%TEST%'
ORDER BY Builders.[Name]

SQL: Chaining Joins Efficiency

I have a query in my WordPress plugin like this:
SELECT users.*, U.`meta_value` AS first_name,M.`meta_value` AS last_name
FROM `nwp_users` AS users
LEFT JOIN `nwp_usermeta` U
ON users.`ID`=U.`user_id`
LEFT JOIN `nwp_usermeta` M
ON users.`ID`=M.`user_id`
LEFT JOIN `nwp_usermeta` C
ON users.`ID`=C.`user_id`
WHERE U.meta_key = 'first_name'
AND M.meta_key = 'last_name'
AND C.meta_key = 'nwp_capabilities'
ORDER BY users.`user_login` ASC
LIMIT 0,10
I'm new to using JOIN and I'm wondering how efficient it is to use so many JOIN in one query. Is it better to split it up into multiple queries?
The database schema can be found here.
JOIN usually isn't so bad if the keys are indexed. LEFT JOIN is almost always a performance hit and you should avoid it if possible. The difference is that LEFT JOIN will join all rows in the joined table even if the column you're joining is NULL. While a regular (straight) JOIN just joins the rows that match.
Post your table structure and we can give you a better query.
See this comment:
http://forums.mysql.com/read.php?24,205080,205274#msg-205274
For what it's worth, to find out what MySQL is doing and to see if you have indexed properly, always check the EXPLAIN plan. You do this by putting EXPLAIN before your query (literally add the word EXPLAIN before the query), then run it.
In your query, you have a filter AND C.meta_key = 'nwp_capabilities' which means that all the LEFT JOINs above it can be equally written as INNER JOINs. Because if the LEFT JOINS fail (LEFT OUTER is intended to preserve the results from the left side), the result will 100% be filtered out by the WHERE clause.
So a more optimal query would be
SELECT users.*, U.`meta_value` AS first_name,M.`meta_value` AS last_name
FROM `nwp_users` AS users
JOIN `nwp_usermeta` U
ON users.`ID`=U.`user_id`
JOIN `nwp_usermeta` M
ON users.`ID`=M.`user_id`
JOIN `nwp_usermeta` C
ON users.`ID`=C.`user_id`
WHERE U.meta_key = 'first_name'
AND M.meta_key = 'last_name'
AND C.meta_key = 'nwp_capabilities'
ORDER BY users.`user_login` ASC
LIMIT 0,10
(note: "JOIN" (alone) = "INNER JOIN")
Try explaining the query to see what is going on and if your select if optimized. If you haven't used explain before read some tutorials:
http://www.learn-mysql-tutorial.com/OptimizeQueries.cfm
http://www.databasejournal.com/features/mysql/article.php/1382791/Optimizing-MySQL-Queries-and-Indexes.htm

Using subselect to accomplish LEFT JOIN

Is is possible to accomplish the equivalent of a LEFT JOIN with subselect where multiple columns are required.
Here's what I mean.
SELECT m.*, (SELECT * FROM model WHERE id = m.id LIMIT 1) AS models FROM make m
As it stands now doing this gives me a 'Operand should contain 1 column(s)' error.
Yes I know this is possible with LEFT JOIN, but I was told it was possible with subselect to I'm curious as to how it's done.
There are many practical uses for what you suggest.
This hypothetical query would return the most recent release_date (contrived example) for any make with at least one release_date, and null for any make with no release_date:
SELECT m.make_name,
sub.max_release_date
FROM make m
LEFT JOIN
(SELECT id,
max(release_date) as max_release_date
FROM make
GROUP BY 1) sub
ON sub.id = m.id
A subselect can only have one column returned from it, so you would need one subselect for each column that you would want returned from the model table.

How can I exclude values from a third query (Access)

I have a query that shows me a listing of ALL opportunities in one query
I have a query that shows me a listing of EXCLUSION opportunities, ones we want to eliminate from the results
I need to produce a query that will take everything from the first query minus the second query...
SELECT DISTINCT qryMissedOpportunity_ALL_Clients.*
FROM qryMissedOpportunity_ALL_Clients INNER JOIN qryMissedOpportunity_Exclusions ON
([qryMissedOpportunity_ALL_Clients].[ClientID] <> [qryMissedOpportunity_Exclusions].[ClientID])
AND
([qryMissedOpportunity_Exclusions].[ClientID] <> [qryMissedOpportunity_Exclusions].[BillingCode])
The initial query works as intended and exclusions successfully lists all the hits, but I get the full listing when I query with the above which is obviously wrong. Any tips would be appreciated.
EDIT - Two originating queries
qryMissedOpportunity_ALL_Clients (1)
SELECT MissedOpportunities.MOID, PriceList.BillingCode, Client.ClientID, Client.ClientName, PriceList.WorkDescription, PriceList.UnitOfWork, MissedOpportunities.Qty, PriceList.CostPerUnit AS Our_PriceList_Cost, ([MissedOpportunities].[Qty]*[PriceList].[CostPerUnit]) AS At_Cost, MissedOpportunities.fBegin
FROM PriceList INNER JOIN (Client INNER JOIN MissedOpportunities ON Client.ClientID = MissedOpportunities.ClientID) ON PriceList.BillingCode = MissedOpportunities.BillingCode
WHERE (((MissedOpportunities.fBegin)=#10/1/2009#));
qryMissedOpportunity_Exclusions
SELECT qryMissedOpportunity_ALL_Clients.*, MissedOpportunity_Exclusions.Exclusion, MissedOpportunity_Exclusions.Comments
FROM qryMissedOpportunity_ALL_Clients INNER JOIN MissedOpportunity_Exclusions ON (qryMissedOpportunity_ALL_Clients.BillingCode = MissedOpportunity_Exclusions.BillingCode) AND (qryMissedOpportunity_ALL_Clients.ClientID = MissedOpportunity_Exclusions.ClientID)
WHERE (((MissedOpportunity_Exclusions.Exclusion)=True));
One group needs to see everything, the other needs to see things they havn't deamed as "valid" missed opportunity as in, we've seen it, verified why its there and don't need to bother critiquing it every single month.
Generally you can exclude a table by doing a left join and comparing against null:
SELECT t1.* FROM t1 LEFT JOIN t2 on t1.id = t2.id where t2.id is null;
Should be pretty easy to adopt this to your situation.
Looking at your query rewritten to use table aliases so I can read it...
SELECT DISTINCT c.*
FROM qryMissedOpportunity_ALL_Clients c
JOIN qryMissedOpportunity_Exclusions e
ON c.ClientID <> e.ClientID
AND e.ClientID <> e.BillingCode
This query will produce a cartesian product of sorts... each and every row in qryMissedOpportunity_ALL_Clients will match and join with every row in qryMissedOpportunity_Exclusions where ClientIDs do not match... Is this what you want?? Generally join conditions are based on a column in one table being equal to the value of a column in the other table... Joining where they are not equal is unusual ...
Second, the second iniquality in the join conditions is between columns in the same table (qryMissedOpportunity_Exclusions table) Are you sure this is what you want? If it is, it is not a join condition, it is a Where clause condition...
Second, your question mentions two queries, but there is only the one query (above) in yr question. Where is the second one?