select only one column distinct mysql - php

I have 3 tables - users, journals, journaltags. I select data from 3 tables using chosen tags.
$sqltheme="SELECT users.id as uid, users.name, users.surname, users.avatar, journals.id, journals.author_id, journals.title, journals.text, journals.create_date, journaltags.name as jname FROM users
INNER JOIN journals ON users.id=journals.author_id
INNER JOIN journaltags ON journaltags.journal_id = journals.id WHERE journals.create_date LIKE ? AND journals.author_id=? AND (".$expression.") ORDER BY journals.id DESC LIMIT 10";
$stmtheme=$conn->prepare($sqltheme);
$stmtheme->execute($array);
But if two tags is the same for one journal then it is selected the same journal two times. How can I make DISTINCT journals.id. I tried GROUP BY journals.id but it didnt help.

If I understand correctly, your problem is that the journaltags table may have one or more rows with a duplicated journal_id and name column value, right?
You can simply add a distinct clause to your select statement, after the word SELECT:
SELECT DISTINCT users.id as uid, users.name, users.surname, users.avatar, journals.id, journals.author_id, journals.title, journals.text, journals.create_date, journaltags.name as jname FROM users
INNER JOIN journals ON users.id=journals.author_id
INNER JOIN journaltags ON journaltags.journal_id = journals.id WHERE journals.create_date LIKE ? AND journals.author_id=? AND (".$expression.") ORDER BY journals.id DESC LIMIT 10
The reason that your GROUP BY journals.id did not work, is because you had other columns that needed to be included in the grouping as well. Adding distinct is essentially a short way of writing group by [all selected columns]

Related

Count for two column from a table using groupby or unionall based on users

I want count for two columns from a single query which are in same table.
1- followerscount
2- followeecount
I am using union and groupby to get count for two columns but only able to get only one column count from query.
Query I used below:
SELECT follow_attr.username, follow_attr.followerid, follow_attr.followeeid, follow_attr.followercount, follow_attr.followeecount
FROM (
SELECT u.username, dff.followerid AS followerid, dff.followeeid AS followeeid, count(dff.followerid) AS followercount, count(dff.followeeid) AS followeecount
FROM tablename AS dff
LEFT JOIN user AS u ON u.userid = dff.followerid
GROUP BY dff.followerid
UNION ALL
SELECT u.username, dffs.followerid AS followerid, dffs.followeeid AS followeeid, count(dffs.followerid) AS followercount, count(dffs.followeeid) AS followeecount
FROM tablename AS dffs
LEFT JOIN user AS u ON u.userid = dffs.followeeid
GROUP BY dffs.followeeid
) AS follow_attr
WHERE follow_attr.username IS NOT NULL
GROUP BY follow_attr.followerid, follow_attr.followeeid
ORDER BY RAND()
LIMIT 0,6
I am not been able to get followeecount in this query.
Let me know whats wrong in that procedure.
Do this
SELECT COUNT(followercount) AS f_count, COUNT(followeecount) AS fe_count FROM tablename

SUM() not working in MySQL : SUM() with DISTINCT

I have 4 tables called shops, users, review and rating.
I want to get all reviews for the corresponding shop with reviewed user details and also overall rating for that shop.
I have done almost with the single query. But the problem is if the shop has same rating for multiple times by same user its consider as single rating. But that rating count was correct.
i.e
from this table user_id 3 was rated shop_id 1 as 4 times. So the count is 4 and total_rating is 17.
My query is
select review.comments, users.username, count(distinct rating.id) as rating_count,
sum(distinct rating.rating) as total_rating from users
left join review on users.id = review.user_id and review.shop_id='1'
left join rating on users.id = rating.user_id and rating.shop_id='1'
where review.shop_id='1' or rating.shop_id='1'
group by users.id, review.user_id, rating.user_id, review.id
When I run this query I got
But I need total_rating 17 for user_id 3..
Check this fiddle
You put DISTINCT IN sum( rating.rating) as total_rating, thats why the result(12=17-5), since it will include 5 only once while computing sum.
select review.comments, review.user_id, count(distinct rating.id) as rating_count,
sum( rating.rating) as total_rating from users
left join review on users.id = review.user_id and review.shop_id='1'
left join rating on users.id = rating.user_id and rating.shop_id='1'
where review.shop_id='1' or rating.shop_id='1'
group by users.id, review.user_id, rating.user_id, review.id
Here is SQLFiddle
Sample Output :
Hope this helps
Try this - Remove the distinct from sum(rating.rating). Since you gave sum(distinct rating.rating), it is ignoring one 5 that user 3 gave to store 1.
select review.comments, users.username, count(distinct rating.id) as rating_count,
sum(rating.rating) as total_rating from users
left join review on users.id = review.user_id and review.shop_id='1'
left join rating on users.id = rating.user_id and rating.shop_id='1'
where review.shop_id='1' or rating.shop_id='1'
group by users.id, review.user_id, rating.user_id, review.id
First of all: It makes no sense to outer-join records from a table and then remove them in the WHERE clause. With left join review ... you say: find a matching record in table review, and if you don't find any, then add nulls, so we keep the users record. Then with where review.shop_id='1' you say: keep only records where you actually found a record in review. So you are dismissing the records that you just took the pain to keep. Your WHERE clause renders your LEFT OUTER JOINS mere INNER JOINS.
As to your actual problem: That stems from joining all tables first and only then trying to get aggregates from the resulting records. Aggregate before joining instead:
select
rev.comments,
usr.username,
coalesce(rat.rating_count, 0) as rating_count,
rat.total_rating
from review rev
join users usr on users.id = review.user_id
left join
(
select user_id, shop_id, count(*) as rating_count, sum(rating) as total_rating
from rating
group by user_id, shop_id
) rat on rat.user_id = usr.id and rat.shop_id = rev.shop_id
where rev.shop_id = 1
group by rev.id;

combine two different queries into one

I have the following query:
SELECT DISTINCT id, title
FROM
((SELECT
DISTINCT offers.id AS id, offers.title AS title
FROM offers
INNER JOIN categories
ON offers.category=categories.title
WHERE categories.title="Fashion clothes"
GROUP BY offers.id
ORDER BY offers.id)
UNION ALL
(SELECT
DISTINCT offers.id AS id, offers.title AS title
FROM offers
INNER JOIN cities
ON offers.city=cities.title
WHERE cities.title="Australia"
GROUP BY offers.id
ORDER BY offers.id)) as subquery
I would like to fetch from the table offers the rows that have category=Fashion clothes and city=Australia but when I use Union it returns all the rows .
I don't know how to make it work. If anyone can help i would appreciate it.
You don't need a union for this. Just join all the tables and have both conditions in you where clause:
SELECT
DISTINCT offers.id AS id, offers.title AS title
FROM offers
INNER JOIN categories
ON offers.category=categories.title
INNER JOIN cities
ON offers.city=cities.title
WHERE categories.title="Fashion clothes" AND cities.title="Australia"
ORDER BY offers.id
As noted by RubahMalam you don't even need the joins as you are joining the tables by title, so the query can be simplified to:
SELECT
DISTINCT offers.id AS id, offers.title AS title
FROM offers
WHERE offers.category="Fashion clothes" AND offers.city="Australia"
ORDER BY offers.id
However, it would probably be best to have separate unique id's in all your tables and use those to join them in your queries, but that's another story.
You just need :
SELECT id,title
FROM offers
WHERE category = "Fashion clothes" OR city = "Australia"
GROUP BY id,title
ORDER BY offers.id
You don't even need INNER JOIN for this. And as patrickh003 said, you don't even need GROUP BY if id is unique column.
If you want both, then you can use aggregation and a having clause:
SELECT o.id, o.title
FROM offers o
WHERE o.category = 'Fashion clothes' AND o.city = 'Australia'
GROUP BY o.id, o.title
HAVING COUNT(*) = 2
ORDER BY o.id;
If you can have duplicates in the offers table, then you need COUNT(DISTINCT o.category) in the HAVING clause instead of COUNT(*).

MySQL Using SUM with multiple joins

I have a projects table and a tasks table I want to do a query that gets all projects and the sum of the time_spent columns grouped by project id. So essentially list all projects and get the total of all the time_spent columns in the tasks table belonging to that project.
With the query posted below I get the latest added time_spent column and not the sum of all the columns.. :S
Below is the query I have at the moment:
SELECT `projects`.`id`, `projects`.`description`, `projects`.`created`,
`users`.`title`, `users`.`firstname`, `users`.`lastname`, `users2`.`title`
as assignee_title, `users2`.`firstname` as assignee_firstname,
`users2`.`lastname` as assignee_lastname,
(select sum(tasks2.time_spent)
from tasks tasks2
where tasks2.id = tasks.id)
as project_duration
FROM (`projects`)
LEFT JOIN `users`
ON `users`.`id` = `projects`.`user_id`
LEFT JOIN `users` as users2
ON `users2`.`id` = `projects`.`assignee_id`
LEFT JOIN `tasks` ON `tasks`.`project_id` = `projects`.`id`
GROUP BY `projects`.`id`
ORDER BY `projects`.`created` DESC
Below is my projects table:
Below is my tasks table:
Thanks in advance!
Usually this query will help you.
SELECT p.*, (SELECT SUM(t.time_spent) FROM tasks as t WHERE t.project_id = p.id) as project_fulltime FROM projects as p
In your question, you don't say about users. Do you need users?
You are on right way, maybe your JOINs can't fetch all data.
This query should do it for you.
Note, whenever you do a group by you must include every column that you select from or order by. Some MySql installations don't prevent you from doing this, but in the end it results in an incorrect result set.
As well you should never do a query as part of your SELECT statement, known as a sub-query, as it will result in an equal amount of additional queries in relation to the number of rows returned. So if you got 1,000 rows back, it would result in 1,001 queries instead of 1 query.
SELECT
p.id,
p.description,
p.created,
u.title,
u.firstname,
u.lastname,
a.title assignee_title,
a.firstname assignee_firstname,
a.lastname assignee_lastname,
SUM(t.time_spent) project_duration
FROM
projects p
LEFT JOIN
users u ON
u.id = p.user_id
LEFT JOIN
users a ON
a.id = u.assignee_id
LEFT JOIN
tasks t ON
t.project_id = p.id
GROUP BY
p.id,
p.description,
p.created,
u.title,
u.firstname,
u.lastname,
a.title,
a.firstname,
a.lastname
ORDER BY
p.created DESC

SQL with multiple joins with same tables

I'm building a forum, and I have a problem with a SQL select with many joins. I want to show two images of different users in the same row.
The first image of the user is who wrote the topic, and the second image is of the user who last replied.
The query I build:
SELECT
posts.*, users.photo, users.displayname FROM posts
JOIN users ON(posts.useraid = users.id)
JOIN users ON(posts.lastreply = user.id)
WHERE forumid='$forumid' and type='post' ORDER BY `timee` DESC
posts.lastreply = the ID of the last reply user.
You have to specify an alias for each table using the AS keyword:
SELECT posts.*,
u1.photo AS creatorPhoto, u1.displayname AS creatorName,
u2.photo AS replierPhoto, u2.displayname AS replierName
FROM posts
JOIN users AS u1 ON(posts.useraid = u1.id)
JOIN users AS u2 ON(posts.lastreply = u2.id)
WHERE forumid= #forumid and type='post'
ORDER BY `timee` DESC
Notice how I call each instance of the users table by a different name - u1 and u2. Also notice how I have specified a column alias to distinguish between the two columns of the same name (e.g. creatorPhoto and replierPhoto). This way you can use the name as an index into a PHP associative array a la $post['creatorPhoto'].
Yes, I've silently changed your inline variable to a parameter. Take it as a hint. :-D
In addition to the lack of aliases in the from clause you may also have a problem with the where and order by clause. You need to use aliases for the columns there.
I don't know where they come from, but something like:
WHERE posts.forumid='$forumid' and posts.type='post'
ORDER BY posts.`timee` DESC
Assuming all come from posts.
you need an alias for this to work
SELECT
posts.*, u1.photo, u1.displayname, u2.photo, u2.displayname FROM posts
JOIN users u1 ON posts.useraid = u1.id
JOIN users u2 ON posts.lastreply = u2.id
WHERE forumid='$forumid' and type='post' ORDER BY `timee` DESC
SELECT posts.*, author.photo as author_photo, author.displayname as author+name,
replier.photo as replier_photo, replier.displayname as replier_name
FROM posts
JOIN users author ON(posts.useraid = users.id)
JOIN users replier ON(posts.lastreply = user.id)
WHERE forumid='$forumid' and type='post' ORDER BY `timee` DESC

Categories