Select Query based on values in result set - mysql

Is there anyway to select all from 1 table based on the result of one query which contains multiple values without having to do 2 separate queries?
Say long join query will produce a list of id's
SELECT xyz FROM table long join query WHERE id = array of ids found in result table
added example:
SELECT * FROM tweets as t
where t.user_id
in(
SELECT uff.id, uff.username
FROM users as uf
LEFT JOIN followlinks as fl
ON uf.id = fl.user_id
LEFT JOIN users as uff
ON fl.follow_id = uff.id
WHERE uff.id = 1
)
The bit in the parenthesis returns an id and user name of who the user is following (uff.id=1)
How do i then get all 'tweets' by all the id's in the generated resultset

You can use subquery:
SELECT * FROM `table1` WHERE `id` IN (SELECT `table2`.id FROM `table2` )
You might want to check documentation for syntax

SELECT xyz FROM table_A join table_B WHERE table_A.id IN (SELECT ID FROM table_C);

I think you mean something like
edited after the OP edit
SELECT * FROM tweets as t
WHERE t.user_id
in(
SELECT uff.id //remove the second field, you just need the id
FROM users as uf
LEFT JOIN followlinks as fl
ON uf.id = fl.user_id
LEFT JOIN users as uff
ON fl.follow_id = uff.id
WHERE uff.id = 1
)

After trying the in clause I coudnt get the results I was after but after rethinking what I was trying to do I got my results with an additional join clause
SELECT uff.username, t.content
FROM users as uf
JOIN followlinks as fl
ON uf.id = fl.user_id
JOIN users as uff
ON fl.follow_id = uff.id
JOIN tweets as t
ON t.user_id = uff.id
WHERE uf.id = 1

Related

Select last record mysql on left join

I have a table that stores all users connections ( date & ip ) and i want to retrieve with a single query all the users data (nickname , avatar ...) + the last record of my connections history table of this user ...
SELECT
*
FROM
`users`
LEFT JOIN
`connections_history` ON `users`.`id` = `connections_history`.`guid`
How i can proceed thx
Assuming that connections_history table has an AUTO_INCREMENT column id:
SELECT *
FROM (
SELECT u.*, MAX(h.id) as hid
FROM users u
LEFT JOIN connections_history h ON u.id = h.guid
GROUP BY u.id
) u
LEFT JOIN connections_history h ON h.id = u.hid
Unfortunately Mysql does not support window functions, you need Correlated sub-query to do this.
Try something like this
SELECT *
FROM users
LEFT JOIN connections_history ch
ON users.id = ch.guid
AND EXISTS (SELECT 1
FROM connections_history ch1
WHERE ch.guid = ch1.guid
HAVING Max(ch1.date) = ch.date)
One way is finding the rows with max date for each guid in subquery and then join with users table.
Like this:
select *
from `users` u
left join (
select *
from `connections_history` c
where date = (
select max(date)
from `connections_history` c2
where c.`guid` = c2.`guid`
)
) t on u.`id` = t.`guid`;
You can do this with a correlated subquery in the ON clause:
SELECT u.*, ch.*
FROM `users` u LEFT JOIN
`connections_history` ch
ON ch.`guid` = u.`id` AND
ch.date = (SELECT MAX(ch2.date)
FROM connections_history ch2
WHERE ch.guid = ch2.guid
);
This formulation allows the query to take advantage of an index on connections_history(guid, date).

Combining select queries

I am working with a MySQL database. I am suppose to combine three select queries, to "improve performance". Each select below is dependent on the previous ID retrieved.
So far, I've tried the following...
# multiple select from tables
select user.name, group.ID
from user as u, group as g
where u.name = <name_here>
# inner join...
select user.ID, group.ID,
from user
inner join group
on user.ID = group.ID
I need to select the user.name and group.ID based on a username param. Is there a way to query this data in a single statement?
I don't know if I understand your need, lets try:
Try to use this query:
select pGroupMatch.GroupID, ProfileData.ID
from pUserMatch
inner join pGroupMatch on pGroupMatch.GroupID = pUserMatch.GroupID
inner join ProfileData on ProfileData.id = pGroupMatch.ProfileID
where pUserMatch.username = "<username>";
Check if you can create indexes for improve your query, if you can try it:
CREATE INDEX idx_pUserMatch_01 ON pUserMatch (GroupID);
CREATE INDEX idx_pGroupMatch_01 ON pGroupMatch (ProfileID);
Please use join for your requirement. Please try below query
select t3.* from Profiles.pUserMatch t1
left join Profiles.pGroupMatch t2 ON t2.GroupID=t1.GroupID
left join Profiles.ProfileData t3 ON t3.ID=t2.ProfileID
where t1.username = "<username>";
I hope above query will help you.Please feel free to comment. Thanks.
This is the query you get by joining the tree queries you already have:
SELECT pd.*
FROM Profiles.ProfileData pd
# ... where ID = "<profile_id>", profile_id = select ProfileID from ...
INNER JOIN Profiles.pGroupMatch pm ON pd.ID = pm.ProfileID
# ... where GroupID = "<group_id>", group_id = select GroupID from ...
INNER JOIN Profiles.pUserMatch pu ON pm.GroupID = pm.GroupID
WHERE pm.username = "<username>"
I put in comments the fragments of your queries that gets converted to JOIN subclauses.
Read more about the syntax of the JOIN subclause of the SELECT statement.
You don't need foreign keys to join stuff:
select p.* from Profiles.pUserMatch u
join Profile.pGroupMatch g on u.GroupID = g.GroupID
join Profile.ProfileData p on g.ProfileID = p.ID
where u.username = ?

Why is this query so slow and what can i do about it

I have the following SELECT UPDATE statement from MySQL
UPDATE table_Learning l
INNER JOIN (select ULN, id from table_users group by ULN having count(ULN) =1) u
ON l.ULN = u.ULN
set l.user_id=u.id
WHERE l.user_id is null
The problem is, it is so slow that it times out, and basically does not work.
I am sure it is to do with the line:
INNER JOIN (select ULN, id from table_users group by ULN having count(ULN) =1) u
and specifically because there is both a GROUP BY and a HAVING clause in this inner select, and from what I have read, because INNER JOINS are very slow with MySQL.
My overall aim is to:
Populate the userID's that are null in table_learning
To do so using the userID's in table_users
To Join on the field named ULN in both tables
To only populate the fields where the ULN is unique in table_users eg if more than one user has this ULN, then do not populate the user_id in table_learning
This is your query:
UPDATE table_Learning l INNER JOIN
(select ULN, id
from table_users
group by ULN
having count(ULN) = 1
) u
ON l.ULN = u.ULN
set l.user_id=u.id
WHERE l.user_id is null;
In MySQL, the subquery is going to be expensive. An index on table_learning(user_id) might help a bit. But filtering inside the subquery could also help:
UPDATE table_Learning l INNER JOIN
(select ULN, id
from table_users
where exists (select 1
from table_learning tl
where tl.ULN = u.uln and tl.user_id is null
)
group by ULN
having count(ULN) = 1
) u
ON l.ULN = u.ULN
set l.user_id=u.id
WHERE l.user_id is null;
For this, you want a composite index on table_learning(ULN, user_id).

Select records where ID from one table is present in one or more other tables

OK, so I've found questions that cover how to do this with only two tables, tons of questions that explain how to do this if the ID does NOT exist in other tables, but not a solution to this query.
Basically, I have one table of wine vintages.
I then have four other tables that contain different types of content that is tied to a specific vintage (i.e. videos, blogs etc.)
I basically need to be able to pull a list of vintages that are in use i.e. where the vintage ID is used in one or more of the four content tables.
The closest I can get is this:
SELECT DISTINCT vintage_id FROM `pr_video_vintage`
INNER JOIN pr_video ON pr_video.fk_vintage_id = pr_video_vintage.vintage_id
INNER JOIN pr_reports ON pr_reports.fk_vintage_id = pr_video_vintage.vintage_id
INNER JOIN pr_reports_notes ON pr_reports_notes.fk_vintage_id = pr_video_vintage.vintage_id
INNER JOIN pr_blog_entries ON pr_blog_entries.fk_vintage_id = pr_video_vintage.vintage_id
ORDER BY `pr_video_vintage`.`vintage_id` ASC
But this (understandably I guess) only returns IDs that exist in ALL of the tables.
What I need is some form of 'OR' JOIN, but can't find any information out about how to go about doing this.
tips? :)
Try this:
SELECT distinct vintage_id FROM `pr_video_vintage`
where exists(select 1 from pr_video where pr_video.fk_vintage_id = pr_video_vintage.vintage_id)
or exists(select 1 from pr_reports where pr_reports.fk_vintage_id = pr_video_vintage.vintage_id)
or exists(select 1 from pr_reports_notes where pr_reports_notes.fk_vintage_id = pr_video_vintage.vintage_id)
or exists(select 1 from pr_blog_entries where pr_blog_entries.fk_vintage_id = pr_video_vintage.vintage_id)
or
SELECT distinct vintage_id FROM `pr_video_vintage`
where pr_video_vintage.vintage_id in (select pr_video.fk_vintage_id from pr_video)
or pr_video_vintage.vintage_id in (select pr_reports.fk_vintage_id from pr_reports)
or pr_video_vintage.vintage_id in (select pr_reports_notes.fk_vintage_id from pr_reports_notes)
or pr_video_vintage.vintage_id in (select pr_blog_entries.fk_vintage_id from pr_blog_entries)
or
SELECT distinct vintage_id FROM `pr_video_vintage`
where pr_video_vintage.vintage_id in (
select pr_video.fk_vintage_id from pr_video
union
select pr_reports.fk_vintage_id from pr_reports
union
select pr_reports_notes.fk_vintage_id from pr_reports_notes
union
select pr_blog_entries.fk_vintage_id from pr_blog_entries)
You can try using an OUTER JOIN or LEFT/RIGHT JOIN. OUTER JOIN computes the cartesian product of all entries including entries that are not present in both tables. LEFT JOIN shows everything in the table in the left hand side of the ON statement whether or not it exists in the right hand side, and RIGHT JOIN does the opposite.
Also, INNER JOIN is the same thing as JOIN if you want to save yourself some keystrokes!
You can run LEFT JOINs, which will return a NULL Id for nonexisting links, combined with a clause to exclude those rows which have all links NULLed.
SELECT DISTINCT vintage_id FROM `pr_video_vintage`
LEFT JOIN pr_video
ON pr_video.fk_vintage_id = pr_video_vintage.vintage_id
LEFT JOIN pr_reports
ON pr_reports.fk_vintage_id = pr_video_vintage.vintage_id
LEFT JOIN pr_reports_notes
ON pr_reports_notes.fk_vintage_id = pr_video_vintage.vintage_id
LEFT JOIN pr_blog_entries
ON pr_blog_entries.fk_vintage_id = pr_video_vintage.vintage_id
WHERE
pr_video.fk_vintage_id IS NOT NULL
OR
pr_reports.fk_vintage_id IS NOT NULL
OR
pr_reports_notes.fk_vintage_id IS NOT NULL
OR
pr_blog_entries.fk_vintage_id IS NOT NULL
ORDER BY `pr_video_vintage`.`vintage_id` ASC

mysql query not recieving any data on my left join

I have a query that on the left join part should either return data or null. But even if there is existing records its not returning any data. The twist to the left join portion is that I would like to only retrieve one record if it exist. Thanks for any help.
select a.*,p.thumbnailphotopath as AlbumPicture
from (select * from album_access) ac
inner join (select * from albums) a on a.ID = ac.AlbumID
left join (
select * from photos
where IsProcessed = 1 order by DateUploaded desc limit 1
) p
on a.ID = p.AlbumID #should return one if exist.
where ac.AccessUserID = '35e44a8e-643a-4c4f-8a46-59911a1e7c53'
and ac.FullControl = 1 and a.Private = 1
First you can just join on a table name and don't need to join on a whole SELECT * FROM statement.
Second, you should try not to use SELECT * and instead SELECT the columns you want.
But I think the problem with your LEFT JOIN is that you're joining on a sub-query that will only return one result, which will be the entry in photos that was last uploaded irrespective of which albumID it belongs to. If you want the entry in photos with the last uploaded date for each row, try something like this
SELECT a.*,p.thumbnailphotopath AS AlbumPicture
FROM album_access ac
INNER JOIN albums a ON a.ID = ac.AlbumID
LEFT JOIN (
SELECT albumID,MAX(DateUploaded) FROM photos
WHERE IsProcessed = 1 GROUP BY albumID
) p ON a.ID = p.AlbumID #should return one if exist.
WHERE ac.AccessUserID = '35e44a8e-643a-4c4f-8a46-59911a1e7c53'
AND ac.FullControl = 1
AND a.Private = 1