Joining Multiple MySQL Statements - mysql

I have multiple queries I perform that I would like to join together.
The first query converts a user supplied path into an id. Paths can have multiple ids associated with them so I want to ensure I get the most recently created id for the path:
SELECT id FROM paths WHERE path=$path ORDER BY created DESC LIMIT 1
Once I know the id number I can perform the rest of my queries.
I have the most recently created id for the path but I need to also verify I have the most recently created path for that id (sometimes they are not the same):
SELECT path FROM paths WHERE id={id} ORDER BY created DESC LIMIT 1
I'd like to include the id's rating and the count of votes though sometimes there are none:
SELECT AVG(vote) AS rating, COUNT(*) AS count FROM votes WHERE id={id} GROUP BY id
Finally I'd like to include everything from a third table about the id (the id is UNIQUE on this table so there cannot be multiple lines):
SELECT * FROM places WHERE id={id}
How can I best join these statements together?

You can join them together into one query like this:
select pl.*, avg(vote) as rating
from (SELECT path, id
FROM paths
WHERE path = {path}
ORDER BY created DESC
LIMIT 1
) p left outer join
votes v
on v.id = p.id left outer join
places pl
on pl.id = p.id
group by p.id;
EDIT:
The first two conditions do seem redundant. But, if you need them:
select pl.*, avg(vote) as rating
from (SELECT path, id
FROM paths
WHERE id = (select id from paths where path = {path} order by created desc limit 1)
ORDER BY created DESC
LIMIT 1
) p left outer join
votes v
on v.id = p.id left outer join
places pl
on pl.id = p.id
group by p.id;

Related

Retrieve records from multiple tables some distinct, some not

I have 4 tables in an existing mysql database of a directory type site.
Table mt_links contains basic info for each listing
Table mt_cl contains which listing above is in what category (I only want cat_id=1)
Table mt_cfvalues contains more details for each listing It Can have repeated values
Table mt_images contains image names for each listing.
I want all records from mt_links where the mt_cl cat_id=1, and for each of those records, I need all records in mt_cfvalues and cf_images matching the link_id.
I set up a select with Group_Concat and left joins, but ended up with repeating values in my results. I added Distinct, which cured the repeating values, but mt_cfvalues can have records with the same value, so now I'm missing a value I should have.
SELECT a.link_id,
a.link_name,
a.link_desc,
GROUP_CONCAT(DISTINCT b.value ORDER BY b.cf_ID) AS details,
GROUP_CONCAT(DISTINCT c.filename ORDER BY c.ordering) AS images
FROM mt_links a
LEFT JOIN mt_cfvalues b ON a.link_id = b.link_ID
LEFT JOIN mt_images c ON b.link_id = c.link_ID
LEFT JOIN mt_cl d ON a.link_id = d.link_ID WHERE d.cat_ID = '1'
GROUP BY a.link_id
I put together a SQLFiddle here: http://www.sqlfiddle.com/#!2/f39e9/1
Is there an easier way? How do I fix the repeating / no repeating issue?
Here is one way of accomplishing what you seek. Because the two subqueries return independent results, you can't combine the GROUP BY, which is why you were getting duplicates.
SELECT a.link_id,
a.link_name,
a.link_desc,
cvf.details,
imgs.images
FROM mt_links a
LEFT JOIN (
SELECT link_ID, GROUP_CONCAT(value ORDER BY cf_ID) AS details
FROM mt_cfvalues
GROUP BY link_ID
) cvf ON cvf.link_ID = a.link_id
LEFT JOIN (
SELECT link_ID, GROUP_CONCAT(filename ORDER BY ordering) AS images
FROM mt_images
GROUP BY link_ID
) imgs ON imgs.link_ID = a.link_id
INNER JOIN mt_cl d ON a.link_id = d.link_ID
WHERE d.cat_ID = '1'

Using UNION, JOIN and ORDER by to Merge 2 identical tables

I need to join 2 identical tables to display the same list sorted by id. (posts and posts2)
It happens that before only worked with 1 table, but we've been using a second table (posts2) to store the new data from a certain id.
This is the query I used when I worked with 1 table(posts) and works fine.
select posts.id_usu,posts.id_cat,posts.titulo,posts.html,posts.slug,posts.fecha,hits.id,hits.hits,usuarios.id,usuarios.usuario,posts.id
From posts
Join hits On posts.id = hits.id
Join usuarios On posts.id_usu = usuarios.id
where posts.id_cat='".$catid."' order by posts.id desc
Now I tried to apply this query to Union 2 tables, but I don't know at what point instantiate the JOINS. I tried several ways but sends MYSQL Error. The following query merge the 2 tables and order by id, but need to add the JOIN.
select * from (
SELECT posts.id,posts.id_usu,posts.id_cat,posts.titulo,posts.html,posts.slug,posts.fecha
FROM posts where id_cat='6' ORDER BY id
)X
UNION ALL
SELECT posts2.id,posts2.id_usu,posts2.id_cat,posts2.titulo,posts2.html,posts2.slug,posts2.fecha FROM posts2 where id_cat='4' ORDER BY id DESC limit 20
I need to add this at the above query
Join hits On posts.id = hits.id
Join usuarios On posts.id_usu = usuarios.id
Thanks in advance guys.
If you want the same query as your first query but this time with union of your identical table i.e post2 then you can do so
select
p.id_usu,p.id_cat,p.titulo,p.html,p.slug,p.fecha
,hits.id,hits.hits,usuarios.id,usuarios.usuario
from (
(select
id_usu,id_cat,titulo,html,slug,fecha ,id
From posts
where id_cat='".$catid."' order by id desc limit 20)
UNION ALL
(select
id_usu,id_cat,titulo,html,slug,fecha ,id
From posts2
where id_cat='".$catid."' order by id desc limit 20)
) p
Join hits On p.id = hits.id
Join usuarios On p.id_usu = usuarios.id
order by p.id desc limit 20

Equivalent to Max() in join query WHERE

I want to be able to write ORDER BY revision_id DESC LIMIT 1 similar to Having Max(revision_id), though that does not behave as I want putting it near the WHERE clause. Putting Max(revision_id) in the select, returns the highest value of the revision ID, but the rest of the fields are not the ones that ought to go with it (it's a in a join).
Query:
SELECT * FROM field_data_field_city
LEFT JOIN profile on(field_data_field_city.entity_id = profile.pid)
LEFT JOIN users on(profile.uid = users.uid)
WHERE users.uid = 1
ORDER BY revision_id DESC
LIMIT 1`
Want to get rid of the limit so I can do it for multiple users at once
I tried with
GROUP BY users.uid
ORDER BY revision_id DESC
But I get the lowest revision_id and I want the highest
You could try below:
WHERE revision_id=(SELECT MAX(revision_id) FROM table)
Assuming the field revision_id is in your table profile you can use:
SELECT *
FROM field_data_field_city
LEFT JOIN profile ON field_data_field_city.entity_id = profile.pid
LEFT JOIN users ON profile.uid = users.uid
WHERE profile.revision_id IN (
SELECT MAX(p.revision_id)
FROM profile p
GROUP BY p.uid) T;

mysql advanced group query

I need some help figuring out a query
I have 3 tables
sources
id, name, rank
origin
id, source_id (FK to sources id), name
One source can have many origins
product
id, origin_id (FK to origin id), name, time_added
One origin can have many products
Now, what I want is to select the most recent products per source, ordered by rank descending
Any suggestions?
This should do as you have requested, though without sample output it's hard to be 100% certain. Inner query selects products linked to the source id ordered by the date added from newest to oldest, and in turn that's joined to sources and grouped.
SELECT
*
FROM sources AS s
INNER JOIN (
SELECT
origins.source_id,
product.*
FROM origin
INNER JOIN product
ON product.origin_id = origin.origin_id
ORDER BY time_added DESC
) AS productsOrdered
ON productsOrdered.source_id = sources.source_id
ORDER BY s.rank DESC, productsOrdered.time_added DESC
This avoids having to do potentially expensive opreations as the inner select should be pretty fast and can be limited as required
A typical way of doing this is to
Find the MAX(time_added) for each origin
Get the product's id for each of these origins
Join with the sources and origin tables to retrieve all columns
Note that this fails if there are origins with multiple records with the exact same time_added.
SQL Statement
SELECT *
FROM sources s
INNER JOIN origin o ON o.source_id = s.id
INNER JOIN product p ON p.origin_id = o.id
INNER JOIN (
SELECT id
FROM product p
INNER JOIN (
SELECT origin_id
, MAX(time_added) AS time_addded
FROM product p
GROUP BY
origin_id
) pmax ON pmax.origin_id = p.origin_id
AND pmax.time_added = p.time_added
) pmax ON pmax.id = p.id
SELECT o.id,count(o.id) as numOfProdFromOrig p.id, p.name, p.time_added, s.rank
FROM product as p NATURAL JOIN sources as s NATURAL JOIN origin as o
GROUP BY (numOfProdFromOrig)
ORDER BY s.rank DESC
select b.id,(select p.name from origin o inner join product p
on p.origin_id = o.id where o.source_id = b.id order by time_added desc limit 1)a as product_name
from source b ;
Try this:

How can I use MySQL to COUNT with a LEFT JOIN?

How can I use MySQL to count with a LEFT JOIN?
I have two tables, sometimes the Ratings table does not have ratings for a photo so I thought LEFT JOIN is needed but I also have a COUNT statement..
Photos
id name src
1 car bmw.jpg
2 bike baracuda.jpg
Loves (picid is foreign key with photos id)
id picid ratersip
4 1 81.0.0.0
6 1 84.0.0.0
7 2 81.0.0.0
Here the user can only rate one image with their IP.
I want to combine the two tables in order of the highest rating. New table
Combined
id name src picid
1 car bmw.jpg 1
2 bike baracuda.jpg 2
(bmw is highest rated)
My MySQL code:
SELECT * FROM photos
LEFT JOIN ON photos.id=loves.picid
ORDER BY COUNT (picid);
My PHP Code: (UPDATED AND ADDED - Working Example...)
$sqlcount = "SELECT p . *
FROM `pics` p
LEFT JOIN (
SELECT `loves`.`picid`, count( 1 ) AS piccount
FROM `loves`
GROUP BY `loves`.`picid`
)l ON p.`id` = l.`picid`
ORDER BY coalesce( l.piccount, 0 ) DESC";
$pics = mysql_query($sqlcount);
MySQL allows you to group by just the id column:
select
p.*
from
photos p
left join loves l on
p.id = l.picid
group by
p.id
order by
count(l.picid)
That being said, I know MySQL is really bad at group by, so you can try putting the loves count in a subquery in your join to optimize it:
select
p.*
from
photos p
left join (select picid, count(1) as piccount from loves group by picid) l on
p.id = l.picid
order by
coalesce(l.piccount, 0)
I don't have a MySQL instance to test out which is faster, so test them both.
You need to use subqueries:
SELECT id, name, src FROM (
SELECT photos.id, photos.name, photos.src, count(*) as the_count
FROM photos
LEFT JOIN ON photos.id=loves.picid
GROUP BY photos.id
) t
ORDER BY the_count
select
p.ID,
p.name,
p.src,
PreSum.LoveCount
from
Photos p
left join ( select L.picid,
count(*) as LoveCount
from
Loves L
group by
L.PicID ) PreSum
on p.id = PreSum.PicID
order by
PreSum.LoveCount DESC
I believe you just need to join the data and do a count(*) in your select. Make sure you specify which table you want to use for ambigous columns. Also, don't forget to use a group by function when you do a count(*). Here is an example query that I run on MS SQL.
Select CmsAgentInfo.LOGID, LOGNAME, hCmsAgent.SOURCEID, count(*) as COUNT from hCmsAgent
LEFT JOIN CmsAgentInfo on hCmsAgent.logid=CmsAgentInfo.logid
where SPLIT = '990'
GROUP BY CmsAgentInfo.LOGID, LOGNAME, hCmsAgent.SOURCEID
The example results form this will be something like this.
77615 SMITH, JANE 1 36
29422 DOE, JOHN 1 648
Hope that helps. Good Luck.