Ok, First see this http://www.sqlfiddle.com/#!2/bbc3a/2
Here the query return the count and all, but what i want is that it selects a forum and return the count of topics and post in it then next forum and all topics and post counts from it and so on with forums name, url and desc. I thought doing this in one query instead of many queries in loop would be better. I don't know what i am doing with that mysql query though, i am not very good with mysql and i haven't sleep for so long. Thanks for help.
EDIT:
This is what i expect to see from the data provided in te fiddle above^
| FORUMNAME | FORUMURL | FORUMDESC | FORUMTIME | TOPICCOUNT | POSTCOUNT |
| Forum 1 | Forum-1 | Forum 1 Desc | 343243243 | 1 | 1 |
| Forum 2 | Forum-2 | Forum 2 Desc | 343243243 | 0 | 0 |
You just need to add a GROUP BY clause
SELECT f.Name ForumName,
f.Url ForumUrl,
f.Desc ForumDesc,
f.Time ForumTime,
COUNT(DISTINCT t.ID) TopicCount,
COUNT(DISTINCT p.ID) PostCount
FROM name_forums f
LEFT JOIN name_topics t ON t.ForumId = f.ID
LEFT JOIN name_posts p ON p.TopicId = t.ID
WHERE f.CategoryId = 1
GROUP BY f.name, f.url, f.desc
Here is SQLFiddle demo
Related
I have two three tables. users, jobs and users_jobs. One user can have many jobs and one job can have many users.
Here is my users table:
+----+------+--------+
| ID | Name | gender |
+----+------+--------+
| 1 | Bob | male |
| 2 | Sara | female |
+----+------+--------+
my jobs table:
+----+----------+
| id | job_id |
+----+----------+
| 1 | Engineer |
| 2 | Plumber |
| 3 | Doctor |
+----+----------+
users_jobs table:
+---------+--------+
| user_id | job_id |
+---------+--------+
| 1 | 1 |
| 1 | 2 |
| 1 | 3 |
| 2 | 1 |
+---------+--------+
As an example, i want to select all males and check if they have at least 1 job and then return their info. If they have no jobs, then don't select/return that user. This is my query:
SELECT * FROM users
INNER JOIN users_jobs
ON users_jobs.user_id = users.id
WHERE users.gender = 'male'
But it returns Bob's info 3 times since he has 3 jobs. I don't want duplicates, how can I get rid of duplicates without using DISTINCT or GROUP BY since performance is very important here.
Thank you!
MySQL allows you to do one a little odd thing, you can select more columns than what's in the GROUP BY clause and aggregate functions (this is not allowed in most other SQL engines). While this sometimes can produce unexpected results, it can work if you don't select data which can appear in multiple rows in the resulting query.
So, for your question - the query WILL return multiple rows for the same user, as some of them have many jobs (busy life, huh?). You generally can't get all their jobs in a single row, as each row is the user's data + their jobs - that's what we JOIN on. But that's not entirely true - you can use GROUP BY and GROUP_CONCAT() to concat all the other data into a single string. I wouldn't generally recommend it, but if its what you need...
SELECT u.Name, GROUP_CONCAT(j.job_id SEPARATOR ', ') as jobs
FROM users u
JOIN users_jobs uj
ON u.ID = uj.user_id
JOIN jobs j
ON j.id = uj.job_id
GROUP BY u.ID
This would return
Name | jobs
--------+-------------------------------
Bob | Engineer, Plumber, Doctor
Sara | Engineer
If you only want males, add in the where clause,
SELECT u.Name, GROUP_CONCAT(j.job_id SEPARATOR ', ') as jobs
FROM users u
JOIN users_jobs uj
ON u.ID = uj.user_id
JOIN jobs j
ON j.id = uj.job_id`
WHERE u.gender = 'male'
GROUP BY u.ID
See live fiddle at http://sqlfiddle.com/#!9/df0afe/2
For this it may will help you,
You can use "Limit" keyword to limit the amount of records fetched
"SELECT * FROM users
INNER JOIN users_jobs
ON users_jobs.user_id = users.id
WHERE users.gender = 'male'" limit 1;
May this will help you!
Thanks!
To follow on from the comments, for performance, it's necessary to use a distinct in your query, try:
SELECT DISTINCT Name FROM users
INNER JOIN users_jobs
ON users_jobs.user_id = users.id
WHERE users.gender = 'male'
If you're looking to get all the columns but keep the id's distinct you can use a GROUP BY, try:
SELECT * FROM users
INNER JOIN users_jobs
ON users_jobs.user_id = users.id
WHERE users.gender = 'male'
GROUP BY users.id
Although this will also effect performance, it depends on what you prioritize the most.
I'm using MySQL.
The result I want, is to display the row with the highest 'time' where 'res' = 'hans', and group the 'frm'.
I am trying to fiddle around with GROUP BY, ORDER BY, MAX(time) - and I'm going no where.
My table: 'messages'
| frm | res | time | msg | opnd |
| poul | hans | 0916 | hi there | 1 |
| john | hans | 1033 | waz up | 1 |
| hans | john | 1140 | new text | 0 |
| poul | john | 1219 | message | 0 |
| poul | hans | 1405 | respond | 0 |
| john | hans | 1544 | write | 0 |
The result I want:
poul - hans - 1405 - respond - 0
john - hans - 1544 - write - 0
The result I get:
poul - hans - 1405 - hi there - 1
john - hans - 1544 - waz up - 1
I'm getting the correct 'time' but the wrong 'msg' and 'opnd'.
My code:
SELECT frm, res, MAX(time), msg, opnd
FROM messages
WHERE res = 'hans'
GROUP BY frm
ORDER BY time DESC
There are a couple ways to do this. One is to use a subquery and join back to the original table:
SELECT m.*
FROM messages m
JOIN (
SELECT frm, res, MAX(time) maxtime
FROM messages
WHERE res = 'hans'
GROUP BY frm, res) m2 on m.frm = m2.frm
and m.res = m2.res
and m.time = m2.maxtime
ORDER BY m.time DESC
Mysql allows you to omit fields from the group by clause that are not used in aggregation (a mistake imo -- most other databases do not allow this behavior). By allowing it, it just returns a random result though which is what you're experiencing.
Here'a another approach using an outer join, but I think the previous is easier to understand:
select m.*
from messages m
left join messages m2 on m.frm = m2.frm
and m.res = m2.res
and m2.time > m.time
where m2.frm is null
and m.res = 'hans'
order by m.time desc
Fiddle Demo With Both
your problem is that you are grouping by one column, but you select several columns with it. As a result, for the other non-grouped by columns you will get just one of the results, not nececarily the one which belongs to the max(time) value.
you need something like:
select a.frm, a.res, b.max_time, a.msg, a.opnd from
messages as a inner join
(SELECT frm, MAX(time) as max_time
FROM messages
WHERE res = 'hans'
GROUP BY frm) on a.frm = b.frm and a.time = b.max_time
ORDER BY time DESC
I have the following (simplified) three tables:
user_reservations:
id | user_id |
1 | 3 |
1 | 3 |
user_kar:
id | user_id | szak_id |
1 | 3 | 1 |
2 | 3 | 2 |
szak:
id | name |
1 | A |
2 | B |
Now I would like to count the reservations of the user by the 'szak' name, but I want to have every user counted only for one szak. In this case, user_id has 2 'szak', and if I write a query something like:
SELECT sz.name, COUNT(*) FROM user_reservations r
LEFT JOIN user_kar k ON k.user_id = r.user_id
LEFT JOIN szak s ON r.szak_id = r.id
It will return two rows:
A | 2 |
B | 2 |
However I want to every reservation counted to only one szak (lets say the highest id only). I tried MAX(k.id) with HAVING, but seems uneffective.
I would like to know if there is a supported method for that in MySQL, or should I first pick all the user ID-s on the backend site first, check their maximum kar.user_id, and then count only with those, removing them from the id list, when the given szak is counted, and then build the data back together on the backend side?
Thanks for the help - I was googling around for like 2 hours, but so far, I found no solution, so maybe you could help me.
Something like this?
SELECT sz.name,
Count(*)
FROM (SELECT r.user_id,
Ifnull(Max(k.szak_id), -1) AS max_szak_id
FROM user_reservations r
LEFT OUTER JOIN user_kar k
ON k.user_id = r.user_id
GROUP BY r.user_id) t
LEFT OUTER JOIN szak sz
ON sz.id = t.max_szak_id
GROUP BY sz.name;
I'm trying to build a commenting system on my website but having issues with ordering the comments correctly. This is a screenshot of what I had before it went wrong:
And this is the query before it went wrong:
SELECT
com.comment_id,
com.parent_id,
com.is_reply,
com.user_id,
com.comment,
com.posted,
usr.username
FROM
blog_comments AS com
LEFT JOIN
users AS usr ON com.user_id = usr.user_id
WHERE
com.article_id = :article_id AND com.moderated = 1 AND com.status = 1
ORDER BY
com.parent_id DESC;
I now want to include each comment's votes from my blog_comment_votes table, using a LEFT OUTER JOIN, and came up with this query, which works, but screws with the order of results:
SELECT
com.comment_id,
com.parent_id,
com.is_reply,
com.user_id,
com.comment,
com.posted,
usr.username,
IFNULL(c.cnt,0) votes
FROM
blog_comments AS com
LEFT JOIN
users AS usr ON com.user_id = usr.user_id
LEFT OUTER JOIN (
SELECT comment_id, COUNT(vote_id) as cnt
FROM blog_comment_votes
GROUP BY comment_id) c
ON com.comment_id = c.comment_id
WHERE
com.article_id = :article_id AND com.moderated = 1 AND com.status = 1
ORDER BY
com.parent_id DESC;
I now get this order, which is bizarre:
I tried adding a GROUP BY clause on com.comment_id but that failed too. I can't understand how adding a simple join can alter the order of results! Can anybody help back on the correct path?
EXAMPLE TABLE DATA AND EXPECTED RESULTS
These are my relevant tables with example data:
[users]
user_id | username
--------|-----------------
1 | PaparazzoKid
[blog_comments]
comment_id | parent_id | is_reply | article_id | user_id | comment
-----------|-----------|----------|------------|---------|---------------------------
1 | 1 | | 1 | 1 | First comment
2 | 2 | 1 | 1 | 20 | Reply to first comment
3 | 3 | | 1 | 391 | Second comment
[blog_comment_votes]
vote_id | comment_id | article_id | user_id
--------|------------|------------|--------------
1 | 2 | 1 | 233
2 | 2 | 1 | 122
So the order should be
First comment
Reply to first comment +2
Second Comment
It's difficult to say without looking at your query results, but my guess is that it's because you are only ordering by parent id and not saying how to order when two records have the same parent id. Try changing your query to look like this:
SELECT
com.comment_id,
com.parent_id,
com.is_reply,
com.user_id,
com.comment,
com.posted,
usr.username,
COUNT(c.votes) votes
FROM
blog_comments AS com
LEFT JOIN
users AS usr ON com.user_id = usr.user_id
LEFT JOIN
blog_comment_votes c ON com.comment_id = c.comment_id
WHERE
com.article_id = :article_id AND com.moderated = 1 AND com.status = 1
GROUP BY
com.comment_id,
com.parent_id,
com.is_reply,
com.user_id,
com.comment,
com.posted,
usr.username
ORDER BY
com.parent_id DESC, com.comment_id;
I have two tables :
users:
___________________________
|user_id | username |
|_______________|___________|
| 1 | Dolly |
| 2 | Didi |
|_______________|___________|
forum:
_____________________________________________________________
|match_static_id| comment | timpstamp | user_id |
|_______________|___________|______________________|__________|
| 1 | Hi | 2013-07-10 12:15:03 | 2 |
| 1 | Hello | 2013-07-09 12:14:44 | 1 |
|_______________|___________|______________________|__________|
this query is working fine and it uses just thw forum table:
SELECT forum.match_static_id,
count(forum.match_static_id) 'comments_no', max(forum.timestamp)'timestamp'
FROM forum
GROUP BY forum.match_static_id
Order BY timestamp DESC
But the following query is using two tables :
SELECT forum.match_static_id,
count(forum.match_static_id) 'comments_no', max(forum.timestamp)'timestamp', users.username
FROM forum
INNER JOIN users on users.id = forum.user_id
GROUP BY forum.match_static_id
Here I want to get the user of the max(timestamp) but i get the wrong user could any body give my a clue about this, please?
Order BY timestamp DESC
Try this:
SELECT f1.match_static_id,
f2.comments_no,
f2.maxtimestamp,
users.username
FROM forum AS f1
INNER JOIN
(
SELECT match_static_id,
max(timestamp) maxtimestamp,
count(comment) AS comments_no
FROM Forum
GROUP BY match_static_id
) AS f2 ON f1.match_static_id = f2.match_static_id
AND f1.timestamp = f2.maxtimestamp
INNER JOIN users on users.user_id = f1.user_id;
See it in action here:
SQL Fiddle Demo