SQL JOIN vars not working - mysql

I'm trying to select variables from 3 tables using 2 left joins.
SELECT a.username, a.id, COUNT(c.featured)
FROM user a
LEFT JOIN board b
ON a.id = b.user_id
LEFT JOIN pins c
ON a.id = c.user_id
WHERE c.featured='yes'
GROUP BY b.board_name
ORDER BY COUNT(c.featured) ASC
LIMIT 3
This should get the 3 highest scoring boards from the database and arrange them according to how many times they have been featured in ascending order. I'm using this to echo:
".$info['b.board_name']."
However nothing is showing

I'm not sure if you want b.boardname or a.username, a.id in your SELECT, but you have to do the GROUP BY accordingly:
Try doing:
SELECT a.username, a.id, COUNT(c.featured)
FROM user a
LEFT JOIN board b ON a.id = b.user_id
LEFT JOIN pins c ON a.id = c.user_id
WHERE c.featured = 'yes'
GROUP BY a.username, a.id
ORDER BY COUNT(c.featured) DESC LIMIT 3
OR
SELECT b.board_name, COUNT(c.featured)
FROM user a
LEFT JOIN board b ON a.id = b.user_id
LEFT JOIN pins c ON a.id = c.user_id
WHERE c.featured = 'yes'
GROUP BY b.board_name
ORDER BY COUNT(c.featured) DESC LIMIT 3

Related

Select count of users over two tables

I want to count the occurrence of the same user id in two tables.
The jos_findme table has all the users in it. The other two have as well the column "user id".
But I want the overall count in the two tables. I tried this but it does not work?
SELECT
c.user_id, count(c.user_id) AS counter
FROM
jos_findme as c
LEFT JOIN
jos_findme_bestof as b ON b.user_id = c.user_id
LEFT JOIN
jos_findme_pair as p ON p.user_id = c.user_id
WHERE
c.user_id > 0
GROUP BY c.user_id
ORDER BY counter DESC
LIMIT 10
ALL tables have the column "user_id". I just want to count them in the tables "jos_findme_bestof" and "jos_findme_pair"
Correlated subqueries could be useful here:
SELECT c.user_id,
(SELECT Count(*)
FROM jos_findme_bestof b
WHERE b.user_id = c.user_id),
(SELECT Count(*)
FROM jos_findme_pair p
WHERE p.user_id = c.user_id)
FROM jos_findme c
Try this
SELECT c.user_id,
Users1 = (SELECT COUNT(*) FROM jos_findme_bestof b WHERE b.user_id = c.user_id),
Users2 = (SELECT COUNT(*) FROM jos_findme_pair p WHERE p.user_id = c.user_id),
TotalUser = (SELECT COUNT(*) FROM jos_findme_bestof b WHERE b.user_id = c.user_id)
+
(SELECT COUNT(*) FROM jos_findme_pair p WHERE p.user_id= c.user_id)
FROM
jos_findme c
Here,
Users1 will return all users from jos_findme_bestof
Users2 will return all users from jos_findme_pair
TotalUser will be count of both the tables
Hope it would helps you!
Thanks.
Try this:
SELECT c.user_id, (IFNULL(b.bCount, 0) + IFNULL(p.pCount, 0)) AS counter
FROM jos_findme AS c
LEFT JOIN (SELECT b.user_id, COUNT(1) bCount
FROM jos_findme_bestof b
GROUP BY b.user_id
) AS b ON b.user_id = c.user_id
LEFT JOIN (SELECT p.user_id, COUNT(1) pCount
FROM jos_findme_pair p
GROUP BY p.user_id
) AS p ON p.user_id = c.user_id
WHERE c.user_id > 0
GROUP BY c.user_id
ORDER BY counter DESC
LIMIT 10
I think you can do something like this:
SELECT AA.user_id, AA.Acounter + BB.Bcounter
from (SELECT a.user_id, count(a.user_id) AS Acounter
FROM jos_findme_bestof as a
GROUP BY a.user_id) as AA
Join
(SELECT b.user_id, count(b.user_id) AS Bcounter
FROM jos_findme_pair as b
GROUP BY b.user_id) as BB
on AA.user_id = BB.user_id
if you wants all the ids (meaning if there are id's in jos_findme_pair that are not in jos_findme_bestof) - use FULL OUTER JOIN

Mysql select count on left join with condition not working

I need to count number of records on left table, i read other questions and end up with this query but the condition on COUNT is ignored
SELECT a.name, COUNT( f.status <> 'e' ) AS total
FROM album AS a LEFT JOIN photo AS f
ON a.id = f.idalbum
WHERE a.iduser = 4
GROUP BY a.id
is MySQL 5 DB
you cant specify a condition inside COUNT statment.
try this
SELECT a.name, COUNT( f.status ) AS total
FROM album AS a LEFT JOIN photo AS f
ON a.id = f.idalbum
WHERE a.iduser = 4 or f.status <> 'e'
GROUP BY a.id
What if you do:
SELECT a.name, COUNT( f.status ) AS total
FROM album AS a LEFT JOIN photo AS f
ON a.id = f.idalbum
WHERE a.iduser = 4 and f.status != 'e'
GROUP BY a.id

Rewrite MySQL Query without NESTED SELECT?

I have a MySQL query that is currently using a nested select, and I am wondering if it is possible to rewrite the query to not use a nested select, and if so how?
The query is as follows
SELECT
b.id,
b.name,
b.description,
b.order,
b.icon,
b.locked,
u.username AS lastPoster,
p.time AS lastPostTime,
p1.subject AS lastPostTopicSubject,
p2.postscount AS totalPosts,
t1.topicscount AS totalTopics,
p.subject AS lastPostSubject,
t.id AS lastPostTopicId
FROM kf_boards AS b
LEFT JOIN kf_topics AS t ON (t.boardid = b.id)
LEFT JOIN (SELECT posterid, topicid, time, subject
FROM kf_posts
ORDER BY time DESC) AS p ON (p.topicid = t.id)
LEFT JOIN (SELECT subject
FROM kf_posts
ORDER BY time ASC) AS p1 ON (p.topicid = t.id)
LEFT JOIN (SELECT COUNT(id) AS postscount
FROM kf_posts) AS p2 ON (p.topicid = t.id)
LEFT JOIN (SELECT COUNT(id) AS topicscount
FROM kf_topics) AS t1 ON (t.boardid = b.id)
LEFT JOIN kf_users AS u ON (p.posterid = u.id)
WHERE b.categoryid = :catid
GROUP BY b.name
ORDER BY b.order
And the database structure is as follows
Any help would be much appriciated!
Thanks!
Edit: Tried below query, results returned
Results should be as follows
try:
SELECT
b.id, b.name, b.description, b.order, b.icon, b.locked,
u.username AS lastPoster, p.time AS lastPostTime,
p.subject AS lastPostSubject, t.id AS lastPostTopicId
FROM kf_boards AS b
LEFT JOIN kf_topics AS t ON t.boardid = b.id
LEFT JOIN kf_posts AS p ON p.topicid = t.id
LEFT JOIN kf_users AS u ON p.posterid = u.id
WHERE b.categoryid = :catid
GROUP BY b.name
ORDER BY b.order ASC, p.time DESC
UPDATE: bellow is for your new query.
SELECT b.id, b.name, b.description, b.order, b.icon, b.locked,
u.username AS lastPoster, MAX(p.time) AS lastPostTime,
p.subject AS lastPostTopicSubject, count(p.id) AS totalPosts,
count(t.id) AS totalTopics, p.subject AS lastPostSubject,
max(t.id) AS lastPostTopicId
FROM kf_boards AS b
LEFT JOIN kf_topics AS t ON t.boardid = b.id
LEFT JOIN kf_posts AS p ON p.topicid = t.id
LEFT JOIN kf_users AS u ON p.posterid = u.id
WHERE b.categoryid = :catid
GROUP BY b.name, b.id, b.name, b.description, b.order, b.icon,
b.locked, u.username, p.subject
ORDER BY b.order
Here's a solution that might help, however, I have additional suggestions to simplify all querying later via triggers. I'll explain that later.
I'm starting with the inner-most query on just board IDs for category (your parameter) and that the board HAS POSTINGS (not via LEFT-JOIN). From this, I am getting just the maximum post ID per board regardless of topic (just that it must be of a valid board per the joins).
Once I have that, the next query out re-joins to the posts table based on the last post to determine the topic... then re-joins THAT to the posts again on the same topic ID. With that, I can get the FIRST Post ID and total Entries for this topic for the board... all grouped per "board ID".
These are obviously only boards that HAVE AT LEAST 1 Board, but that's not what you want. You want ALL boards regardless of a post. So, I'm back to the beginning to query kf_boards again with same WHERE on category ID = your parameter... THIS gets you all the boards for the category...
NOW, you can left-join to the pre-aggregate query for min/max post and entries count... Then take THAT to left-join to the posts table again but TWICE... Once for the FIRST post (so you can get the initial subject caption, time and whatever else you might care about), and AGAIN for the LAST POST to get ITs time, subject, etc... You already have the total post entries for this topic from the pre-aggregate query. Finally, a left-join on the last post to the users table to see who posted it last.
I've tested the syntax on it and it works, just can't confirm based on actual data.
SELECT
B.ID,
B.Name,
B.Description,
B.Order,
B.Icon,
FP.Subject as FirstPostSubject,
FP.Time as FirstPostTime,
LP.Subject as LastPostSubject,
LP.Time as LastPostTime,
U.UserName as LastPostUserName,
QryPerBoard.PostEntries
from
kf_boards B
LEFT JOIN
( select
PQ1.ID,
PQ1.LastPostID,
MIN( P2.ID ) as FirstPostID,
COUNT(*) as PostEntries
from
( SELECT
B1.ID,
MAX( P1.ID ) as LastPostID
from
kf_boards B1
join kf_topics T1
ON B1.ID = T1.BoardID
join kf_posts P1
ON T1.ID = P1.TopicID
where
B1.CategoryID = 1 <-- Insert your Category Parameter ID here
group by
B1.ID ) as PQ1
LEFT JOIN kf_posts P1
ON PQ1.LastPostID = P1.ID
LEFT JOIN kf_posts P2
ON P1.TopicID = P2.TopicID
group by
PQ1.ID ) QryPerBoard
ON B.ID = QryPerBoard.ID
LEFT JOIN kf_posts FP
ON QryPerBoard.FirstPostID = FP.ID
LEFT JOIN kf_posts LP
ON QryPerBoard.LastPostID = LP.ID
LEFT JOIN kf_users U
ON LP.PosterID = U.ID
where
B.CategoryID = 1 <-- Insert your Category Parameter ID here (second copy for parameter)
Now, how I would adjust to prevent the recursive level of querying, especially for a website. Use triggers. When a POST is created and saved, have a trigger that does a few things...
REVISED THOUGHT on trigger impact.
Update the kf_Boards with the latest TOPIC ID any post was created for the respective board ID so you never have to look for it later, just take whatever is the last and run with it. In addition, update the TOPIC record. Have a column for the FIRST POST, LAST POST and TOTAL POSTS for the topic. If its the first post to the topic, update both first AND last post with the new ID and increment the total post count.
The time to incorporate these triggers to update the "extra" columns would save such complexities for future queries. You'll basically be able to do something like
select
B.*,
LP.Fields, <obviously apply specific fields you want per table>
FP.Fields,
U.Fields
from
kf_boards B
LEFT JOIN kf_topics T
on B.LastTopicID = T.ID
LEFT JOIN kf_posts FP
on T.FirstPostID = FP.ID
LEFT JOIN kf_posts LP
on T.LastPostID = LP.ID
LEFT JOIN kf_users U
on LP.PosterID = U.ID
where
B.CategoryID = 1 <-- your parameterID
It seems possible to remove all the subqueries,
but the query will be more clear if the last post, and the first post on the corresponding
topic is found using subqueries:
SELECT b.id, b.name, b.description, b.sortorder, b.icon, b.locked,
u.username AS lastPoster,
p1.time AS lastpostTime,
p0.subject AS lastPostTopicSubject,
COUNT(DISTINCT p.id) AS totalPosts,
COUNT(DISTINCT t.id) AS totalTopics,
p1.subject AS lastPostSubject,
p1.topicid AS lastPostTopicId
FROM kf_boards b
LEFT JOIN kf_topics t ON t.boardid = b.id
LEFT JOIN kf_posts p ON p.topicid = t.id
LEFT JOIN kf_posts p1
ON p1.time = (SELECT MAX(time) FROM kf_posts p
INNER JOIN kf_topics t
ON p.topicid = t.id
WHERE t.boardid = b.id)
LEFT JOIN kf_users u ON u.id = p1.posterid
LEFT JOIN kf_posts p0
ON p0.time = (SELECT MIN(time) FROM kf_posts p0
WHERE p0.topicid = p1.topicid)
WHERE b.categoryid = :catid
GROUP BY b.id
ORDER BY b.sortorder;
However, the following query, using self joins to find posts that have no related previous/nest post should give the same answer:
SELECT b.id, b.name, b.description, b.sortorder, b.icon, b.locked,
u.username AS lastPoster,
lastpost.time AS lastpostTime,
firstpost.subject AS lastPostTopicSubject,
COUNT(DISTINCT p.id) AS totalPosts,
COUNT(DISTINCT t.id) AS totalTopics,
lastpost.subject AS lastPostSubject,
lastpost.topicid AS lastPostTopicId
FROM kf_boards b
LEFT JOIN kf_topics t ON t.boardid = b.id
LEFT JOIN kf_posts p ON p.topicid = t.id
LEFT JOIN kf_topics lasttopic ON lasttopic.boardid = b.id
LEFT JOIN kf_posts lastpost ON lastpost.topicid = lasttopic.id
LEFT JOIN kf_topics nexttopic ON nexttopic.boardid = b.id
LEFT JOIN kf_posts nextpost -- order posts
ON nextpost.topicid = nexttopic.id -- in same board
AND nextpost.time > lastpost.time -- by time
LEFT JOIN kf_users u ON u.id = lastpost.posterid
LEFT JOIN kf_posts AS firstpost ON firstpost.topicid = lastpost.topicid
LEFT JOIN kf_posts prevpost -- order posts
ON prevpost.topicid = firstpost.topicid -- on same topic
AND prevpost.time < firstpost.time -- by time
WHERE nextpost.id IS NULL -- last post has no next
AND prevpost.id IS NULL -- first post on topic has no previous
AND b.categoryid = :catid
GROUP BY b.id
ORDER BY b.sortorder;
Check the result at http://sqlfiddle.com/#!2/1c042/1/0

Mysql Join issue and i want this result

I have two tables 1 and 2 or i need this result (see my image 1) using Join in mysql also see my Query for verification
SELECT c.`id`,
c.`name`,
COUNT(*) AS `totalcount`
FROM categories c INNER JOIN subcategories sc
ON c.`id` = sc.`cat_id`
GROUP BY c.`id`
ORDER BY c.added_date DESC
I want this result
Table 1
Table 2
Help are definitely appreciated
USE LEFT JOIN instead of INNER JOIN
try this:
SELECT a.`id`, a.`name`, count(b.`cat_id`) as totalCount
FROM categories a LEFT JOIN subcategories b
on a.id = b.cat_ID
GROUP BY a.`id`
ORDER BY a.added_date desc
Use LEFT JOIN instead of INNER JOIN -
SELECT c.`id`, c.`name`,
COUNT(sc.cat_id) AS `totalcount`
FROM categories c LEFT JOIN
subcategories sc
ON c.`id` = sc.`cat_id`
GROUP BY c.`id`
ORDER BY c.added_date DESC;
A demo is here.

Make SQL query from four table

My database have got 4 table :
users
id
username
images
id
user_id
image
user_follow
user_id
user_follow
commentaries
image_id
text
I try to make a query to get all my and my friends pictures
1) row must be shown only if user have picture in "images" table
2) only image from me and my friends (depending on "user_follow" table)
3) count commentaries for each picture
my query is:
SELECT u.username as user, i.image as user_image, p.image, UNIX_TIMESTAMP(p.date) as date, COALESCE ( imgcount.cnt, 0 ) as comments
FROM users u
LEFT JOIN user_follow f ON u.id = f.follow_id
LEFT JOIN images p ON p.user_id = u.id
LEFT JOIN images i ON i.id = (SELECT b.id FROM images AS b where p.user_id = b.user_id ORDER BY b.id DESC LIMIT 1)
LEFT JOIN (SELECT image_id, COUNT(*) as cnt FROM commentaries GROUP BY image_id ) imgcount ON p.id = imgcount.image_id
WHERE f.user_id = 3 OR p.user_id = 3
ORDER BY p.date DESC
Commentaries count of each image sql line works fine in this query
LEFT JOIN (SELECT image_id, COUNT(*) as cnt FROM commentaries GROUP BY image_id ) imgcount ON p.id = imgcount.image_id
in this line I try to get user his last upload image as avatar from "images" table
LEFT JOIN images i ON i.id = (SELECT b.id FROM images AS b where p.user_id = b.user_id ORDER BY b.id DESC LIMIT 1)
This query dot not return result correctly because it show my friends who do not have pictures and something is not good with my own pictures (in database I have 2 row with my user_id : 3 ) but sql return 4
If I'm understanding correctly, it seems like you've made this a lot more complex than it needs to be. The reason you are getting records for your friends without pictures is because you are using a LEFT JOIN. Change that to an INNER JOIN and you will only get the records that match the join condition.
I think you are looking for something like the following. You'll need to make a few tweaks but hopefully this helps.
SELECT u.username as user, i.image as user_image, count(*) as comments
FROM users u
INNER JOIN user_follow f ON u.id = f.follow_id
INNER JOIN images p ON p.user_id = u.id
INNER JOIN commentaries c ON c.image_id = p.id
WHERE u.user_id = 3
GROUP BY u.username, i.image;