SQL group result in one row - mysql

I have the I site a database that handles 7 different languages, I want to return in one row all the post_content in one row.
Example:
fr_content,en_content,es_content,int_content...
My current sql is returning 7 rows
My sql is:
SELECT p.ID, t.trid, ptrans.*, pen.post_content
FROM hex_posts p
JOIN hex_icl_translations t
ON p.ID = t.element_id
LEFT JOIN hex_icl_translations ptrans
on ptrans.trid = t.trid
LEFT JOIN hex_posts pen
on pen.ID = ptrans.element_id
WHERE
p.ID = 22790
ORDER BY p.post_date DESC
The ID 22790 is the original post, element_id is the post translated.
Any idea how to group all this rows in just one?
Thanks

use group_concat()
SELECT p.ID, t.trid, ptrans.*, group_concat(pen.post_content SEPARATOR ', ')
FROM hex_posts p
JOIN hex_icl_translations t
ON p.ID = t.element_id
LEFT JOIN hex_icl_translations ptrans
on ptrans.trid = t.trid
LEFT JOIN hex_posts pen
on pen.ID = ptrans.element_id
WHERE
p.ID = 22790
group by p.ID, t.trid
ORDER BY p.post_date DESC

Related

How to properly join these three tables in SQL?

I'm currently creating a small application where users can post a text which can be commented and the post can also be voted (+1 or -1).
This is my database:
Now I want to select all information of all posts with status = 1 plus two extra columns: One column containing the count of comments and one column containing the sum (I call it score) of all votes.
I currently use the following query, which correctly adds the count of the comments:
SELECT *, COUNT(comments.fk_commented_post) as comments
FROM posts
LEFT JOIN comments
ON posts.id_post = comments.fk_commented_post
AND comments.status = 1
WHERE posts.status = 1
GROUP BY posts.id_post
Then I tried to additionally add the sum of the votes, using the following query:
SELECT *, COUNT(comments.fk_commented_post) as comments, SUM(votes_posts.type) as score
FROM posts
LEFT JOIN comments
ON posts.id_post = comments.fk_commented_post
AND comments.status = 1
LEFT JOIN votes_posts
ON posts.id_post = votes_posts.fk_voted_post
WHERE posts.status = 1
GROUP BY posts.id_post
The result is no longer correct for either the votes or the comments. Somehow some of the values seem to be getting multiplied...
This is probably simpler using correlated subqueries:
select p.*,
(select count(*)
from comments c
where c.fk_commented_post = p.id_post and c.status = 1
) as num_comments,
(select sum(vp.type)
from votes_posts vp
where c.fk_voted_post = p.id_post
) as num_score
from posts p
where p.status = 1;
The problem with join is that the counts get messed up because the two other tables are not related to each tother -- so you get a Cartesian product.
You want to join comments counts and votes counts to the posts. So, aggregate to get the counts, then join.
select
p.*,
coalesce(c.cnt, 0) as comments,
coalesce(v.cnt, 0) as votes
from posts p
left join
(
select fk_commented_post as id_post, count(*) as cnt
from comments
where status = 1
group by fk_commented_post
) c on c.id_post = p.id_post
left join
(
select fk_voted_post as id_post, count(*) as cnt
from votes_posts
group by fk_voted_post
) v on v.id_post = p.id_post
where p.status = 1
order by p.id_post;

INNER JOIN LIMIT 1 WITH USING PAGINATION

How do i limit inner join to 1 with order by DESC on this part
INNER JOIN comments ON thread.t=comments.comment_id
this is my code https://gist.github.com/anonymous/cf7de8400327b98631d2f6d9b23084b5
look at result output there is the problem on duplicate content because of comments (need to limit 1) #M Khalid Junaid
Do a self join to your comments table to pick the recent comment only for each post
SELECT
t.t_dp,
t.t,
t.t_id,
t.tittle,
t.t_username,
t.t_date_posting,
t.views,
c.comments,
c.comment_time,
c.comment_id,
c.c
FROM
thread t
INNER JOIN comments c
ON t.t = c.comment_id
LEFT JOIN comments c1
ON c.comment_id = c1.comment_id
AND c.id < c1.id
WHERE t.t_type = '02'
AND c1.id IS NULL
LIMIT #start_from, #results_per_page
Also you are using LIMIT without ORDER BY which makes no sense, In which order limit applies on records.

How to ORDER BY/MAX before GROUP BY after a LEFT JOIN to a many table?

There are 3 tables in question - properties, specials, and properties_specials.
I want n results back where n is the number of properties, and the corresponding special is the one with the MAX(specials.startdate).
I first tried doing this after aggregation but the MIN/MAX doesn't seem to affect the result set at all:
SELECT
p.id,
s.*,
MAX( s.startdate )
FROM
properties p
LEFT JOIN properties_specials ps ON ps.properties_id = p.id
LEFT JOIN specials s ON s.id = ps.specials_id
GROUP BY p.id
Using a subquery with max doesn't work because it just grabs the total max:
SELECT
p.id,
s.*
FROM
properties p
LEFT JOIN properties_specials ps ON ps.properties_id = p.id
LEFT JOIN (
SELECT id, MAX( specials.startdate )
FROM specials
) AS s ON s.id = ps.specials_id
GROUP BY p.id
And finally doing an ORDER BY in the subquery doesn't seem to work either because even though I specify ORDER BY specials.startdate DESC or ORDER BY specials.startdate ASC, the result is the same for:
properties table
id name
----------------
11 Hotel
properties_specials table
properties_id specials_id
----------------
11 33
11 34
specials table
id startdate
----------------
33 2016-01-02
34 2016-01-10
How can I adjust this properly so I get the most recent / max after the join to properties_specials?
EDIT: Came up with a sqlfiddle for this. I think the differing factor may have been that the same special can be applied to different properties in the mapping table - if that's the case sorry for not specifying earlier.
You can do this by using an aggregation to get the maxdate per property and then joining these back in:
select p.*, s.*
from properties p join
(select ps.properties_id, max(s.startdate) as maxsd
from properties_specials ps join
specials s
on s.id = ps.specials_id
group by ps.properties_id
) maxps
on p.id = maxps.properties_id join
properties_specials ps
on ps.properties_id = p.id join
specials s
on ps.specials_id = s.id and s.startdate = maxps.maxsd;
EDIT:
Note the above query had an error. It was missing an on clause, which resulted in many duplicates (and would have been an error in any database other than MySQL).
Another approach is to just use the id instead of the date. Plugging directly into the above query:
select p.*, s.*
from properties p join
(select ps.properties_id, max(s.id) as maxid
from properties_specials ps join
specials s
on s.id = ps.specials_id
group by ps.properties_id
) maxps
on p.id = maxps.properties_id join
properties_specials ps
on ps.properties_id = maxps.properties_id join
specials s
on s.id = maxps.maxid;
Here is the quick answer:
SELECT ps.properties_id, max(s.startdate)
FROM specials s, properties_specials ps
WHERE s.id = ps.specials_id
GROUP BY 1
If you want all the information, try the following:
SELECT p.id pid, p.name, s.id sid, s.startdate
FROM properties p, specials s, properties_specials ps, (
SELECT ps.properties_id pid, max(s.startdate) maxdate
FROM specials s, properties_specials ps
WHERE s.id = ps.specials_id
GROUP BY 1
) as pmax
WHERE p.id = ps.properties_id AND s.id = ps.specials_id
AND p.id = pmax.pid AND pmax.maxdate = s.startdate

GROUP BY and ORDER BY issues

I have the following query:
SELECT DISTINCT (
s.styleTitle
), COUNT(p.id) AS `PictureCount`
FROM `style` s
LEFT JOIN `instagram_picture_style` ps ON s.id = ps.style_id
LEFT JOIN `instagram_shop_picture` p ON ps.picture_id = p.id
LEFT JOIN `instagram_picture_category` c ON c.picture_id = p.id
LEFT JOIN `instagram_second_level_category` sl ON c.second_level_category_id = sl.id
WHERE sl.id =25
GROUP BY p.id
ORDER BY PictureCount
however this query gives me:
I basically wanted the list to be ordered by the style that has the most pictures in it. What did I do wrong? Why is it giving me 1 on all of the styles, I am pretty sure it has more pictures for that style
ORDER BY doesn't have underscores. But equally important, you are using DISTINCT in a way where you seem to think that it is a function. It is not. It is a modifies on the SELECT and it applies to all columns.
You should group by the same column you have in the distinct. Something like this:
SELECT s.styleTitle, COUNT(p.id) AS `PictureCount`
FROM `style` s
LEFT JOIN `instagram_picture_style` ps ON s.id = ps.style_id
LEFT JOIN `instagram_shop_picture` p ON ps.picture_id = p.id
LEFT JOIN `instagram_picture_category` c ON c.picture_id = p.id
LEFT JOIN `instagram_second_level_category` sl ON c.second_level_category_id = sl.id
WHERE sl.id = 25
GROUP BY s.styleTitle
ORDER BY PictureCount DESC;
In fact, you almost never need distinct with group by. If you are using, you need to think why it would be necessary.

Gathering multiple fields

$q = "SELECT s.id, s.title, s.description,
(SELECT COUNT(*) FROM ".FORUM_THREADS." t WHERE t.cat_id = s.id) AS topics,
(SELECT COUNT(*) FROM ".FORUM_REPLIES." r INNER JOIN ".FORUM_THREADS." t ON r.thread_id = t.id
WHERE t.cat_id = s.id) AS replies,
(SELECT r.date FROM ".FORUM_REPLIES." r INNER JOIN ".FORUM_THREADS." t ON r.thread_id = t.id
WHERE t.cat_id = s.id ORDER BY r.date DESC LIMIT 1) AS last_post
FROM ".FORUM_SUBCATEGORIES." s WHERE s.parent = '$catid' AND s.status = '0' ORDER BY s.id";
I am attempting to select more than one field on the following part of the query
(SELECT r.date FROM ".FORUM_REPLIES." r INNER JOIN ".FORUM_THREADS." t ON r.thread_id = t.id
INNER JOIN ".TBL_USERS." u ON u.id = r.author WHERE t.cat_id = s.id ORDER BY r.date DESC LIMIT 1) AS last_post
Along with r.date, I want to select u.username and r.author.
How can I go about doing this?
Thanks!
Just add them to the SELECT:
(SELECT r.date, r.author, u.username FROM ".FORUM_REPLIES." r INNER JOIN ".FORUM_THREADS." t ON r.thread_id = t.id
INNER JOIN ".TBL_USERS." u ON u.id = r.author WHERE t.cat_id = s.id ORDER BY r.date DESC LIMIT 1) AS last_post
UPDATED after comment from OP:
You need to do 3 separate selects OR (depending on your data model) change the query so that the last_post query ends up after/in the FROM clause (there it can have as many columns as you want)...
Luke, you have a central select statement which uses nested select statements for getting the count. You can't depend on the nested select statements to count as the inner join, so you're going to have to add them to the central select statement instead.
In other words, join ".FORUM_REPLIES." and "u" (not sure what that's supposed to represent) with ".FORUM_SUBCATEGORIES.". I'd write the query for you, but I don't know how to link subcategories with replies and subcategories with u.