MySQL - Issue with SELECT & GROUP BY - mysql

Hello the wonderful community,
I have a basic config MySQL / PHP with this DB :
Pages Table
Tags Table
Pages_Tags Table
Query :
SELECT *, GROUP_CONCAT('tags_name')
FROM pages
LEFT JOIN pages_tags ON pages_tags.pages_id = pages.pages_id
LEFT JOIN tags ON tags.tags_id = pages_tags.tags_id
GROUP BY pages_tags.pages_id;
and i have the following error :
"Expression #1 of SELECT list is not in GROUP BY clause and contains
nonaggregated column this is incompatible with sql_mode=only_full_group_by"
So i made a lot of researches, and seems there are 2 solutions :
1/ To change the SQL mode
2/ To have the same column in the SELECT & GROUP BY.
Both seems bad solutions. The first because i don't want to change the default config and the second is insane, i need a lot of columns in the SELECT and not only the GROUP BY. Especially if the query is more complicated with a lot more LEFT JOIN. I need to display all theses infos.
Do you have any solutions ? Alternative with other methods ?
I'm open to anything ;)
Thanks a lot !!

starting from mysql 5.7 you can use column in select not involved in aggreagtion function and not mentioned in group by clause, so you should not use * (all) for column but add explict column name in select and mention the column in select not involved in aggregation function in group by
SELECT `pages_tags`.`pages_id`, GROUP_CONCAT('tags_name')
FROM `pages`
LEFT JOIN `pages_tags` ON `pages_tags`.`pages_id` = `pages`.`pages_id`
LEFT JOIN `tags` ON `tags`.`tags_id` = `pages_tags`.`tags_id`
GROUP BY `pages_tags`.`pages_id`

Related

inner join with COUNT() and GROUP BY

I am using phpMyAdmin to test this query but keep getting a syntax error. I've tried looking it up in the MySql manual and trying other syntactical possibilities but I've gotten older in this process. Thanks for your help
SELECT image_title, image_id, COUNT(other_sales.*) FROM art
INNER JOIN other_sales ON (art.image_id=other_sales.image_id)
GROUP BY (other_sales.image_id);
MySQL said: Documentation
Documentation
1052 - Column 'image_id' in field list is ambiguous
Ultimately, I want to count the number of times a specific number (image_id) occurs in the 'other_sales' table
To troubleshoot these 1064 errors:
The error message gives a snippet of your query. The first character of the snippet is the first character the MySQL interpreter could not understand.
So in the case of your query, it's
SELECT image_title, image_id, COUNT(other_sales.*) FROM art INNER JOIN ...
ggggggggggggggggggggggggggggggggggggggggggggggggbbbbbbbbbbbbbbbbbbbbbbbbbbb
where g means good and b means bad.
Your actual problem: you can't put more than one value in a COUNT() function. You tried to put COUNT(something.*) which makes no sense to count.
Notice that COUNT(*) is a special case meaning just count the rows.
the tables art and other sales probably both have the column image_id.
specify the table before the column like art.imageid or asign a alias to the table and then to the column like so
SELECT o.image_title, o.image_id, COUNT(*)
FROM art a JOIN other_sales o ON (art.id=other_sales.image_id)
GROUP BY (o.image_id)
Yes, I see that now. There are 2 problems with my original code.
I should have chosen the specific column name instead of using *
image_id is a column name that appears in both tables I am accessing. That will cause an "ambiguous" error.
Below is the original code and the corrected code:
original:
SELECT image_title, image_id, COUNT(other_sales.*) FROM art INNER JOIN other_sales ON (art.image_id=other_sales.image_id) GROUP BY (other_sales.image_id);
corrected:
SELECT image_title, art.image_id, COUNT(other_sales.image_id) FROM art INNER JOIN other_sales ON (art.image_id=other_sales.image_id) GROUP BY (other_sales.image_id);
thanks for the help

An efficient way to write MySql query that has duplicate column names

I have a reasonably straightforward MySQL query as follows:
SELECT *
FROM post INNER JOIN comment ON post.post_id = comment.post_id
WHERE post.host = 99999
ORDER BY post.post_id
My problem is that some of my column names are common to both the post and comment table. In the result, the column name appears only once, and its values are taken from the last table in the query (ie. the comment table).
I realise that I could explicitly list each column name in the SELECT part of the query, and use aliases to differentiate between duplicate column names, but there are a lot of columns in each table and it would be messy.
Is there a more efficient way to go about it?
You should just use aliases for those columns that are alike and then * for the rest:
SELECT post.post_id, comment.post_id as comment_post_id, *
FROM ...
I don't think there is a better approach.
Good luck.
Listing column names is always a better approach as long as it is feasible, it may give some hint to the MySQL optimizer.
Additionally, I would use Using syntax when the Join is done on similar column name.
SELECT x.x1, x.x2 ... , y.x1, y.x2 ...
FROM post as x
INNER JOIN comment as y
USING post_id
WHERE ...
You can select all the column from both the table.Just give an alias to the both table name and the use alias.* after select statement.
Then it will select all the column from the table.
Example:
SELECT pst.*,cmt.* from post pst INNER JOIN comment cmt
FROM ...

Subtle difference between queries?

In the article Why Arel?, the author poses the problem:
Suppose we have a users table and a photos table and we want to select all user data and a *count* of the photos they have created.
His proposed solution (with a line break added) is
SELECT users.*, photos_aggregation.cnt
FROM users
LEFT OUTER JOIN (SELECT user_id, count(*) as cnt FROM photos GROUP BY user_id)
AS photos_aggregation
ON photos_aggregation.user_id = users.id
When I attempted to write such a query, I came up with
select users.*, if(count(photos.id) = 0, null, count(photos.id)) as cnt
from users
left join photos on photos.user_id = users.id
group by users.id
(The if() in the column list is just to get it to behave the same when a user has no photos.)
The author of the article goes on to say
Only advanced SQL programmers know how to write this (I’ve often asked this question in job interviews I’ve never once seen anybody get it right). And it shouldn’t be hard!
I don't consider myself an "advanced SQL programmer", so I assume I'm missing something subtle. What am I missing?
I believe your version would produce an error, at least in some database engines. In MSSQL your select would generate [Column Name] is invalid in the select list because it is not contained in either an aggregate function or the GROUP BY clause.. This is because you select can only contain values in the group by or the count.
You could modify your version to select users.id, count(photo.id) and it would work, but it would not be the same result as his query.
I would not say you have to be particularly advanced to come up with a working solution (or the specific solution he came up with) but it is necessary to do the group in a separate query either in the join or as #ron tornambe suggests.
In most DBMSs (MySQL and Postgres are exceptions) the version in your question would be invalid.
You would need to write the query which does not use the derived table as
select users.*, CASE WHEN count(photos.id) > 0 THEN count(photos.id) END as cnt
from users
left join photos on photos.user_id = users.id
group by users.id, users.name, users.email /* and so on*/
MySQL allows you to select non aggregated items that are not in the group by list but this is only safe if they are functionally dependant on the column(s) in the group by.
Whilst the group by list is more verbose without the derived table I would expect most optimisers to be able to transform one to the other anyway. Certainly in SQL Server if it sees you are grouping by the PK and some other columns it doesn't actually do group by comparisons on those other columns.
Some discussion about this MySQL behaviour vs standard SQL is in Debunking GROUP BY myths
Maybe the author of the article is wrong. Your solution works as well, and it may very well be faster.
Personally, I would drop the if alltogether. If you want to count the number of pictures, it makes sense that 'no pictures' results in 0 rather than null.
As an alternative, you can also write a correlated sub-query:
SELECT u.*, (SELECT Count(*) FROM photos p WHERE p.userid=u.id) as cnt
FROM users u

MySQL Combine Data + Count(*) Query FROM 2 tables

I need help with an query. I have a 'members' table and a 'comments' table.
members: userid,name,bday etc...
comments: id,userid,message,rel etc...
Untill now i used 2 queries for membersdata and commentsCount, and combined both in PHP.
My Question. Is it possible to get both (all from members && count of comments) in only one query?
This is not workung...
SELECT members.*, count(comments.*) as count
FROM members, comments
WHERE members.userid=comments.userid
group by members.userid
Does somebody know an other solution?
Here's a cleaned-up version of your query, assuming you want the userid and number of comments for each:
SELECT members.userid, count(*) as count
FROM members
INNER JOIN comments
ON members.userid = comments.userid
GROUP BY members.userid
The issues I addressed:
only selected columns that are either in the group by clause, or have an aggregate function applied to them. It is incorrect to select columns which don't satisfy either of those criteria (although MySQL allows you to do it)
replaced implicit join with explicit join, and moved join condition from where clause to on clause
replaced select ... count(comments.*) with select ... count(*). count(*) works just fine
Thank you Matt
I used your version. And im learning by the was sql-joins.
The problem with my code was the 'count(comments.*)'. Mysql does not like this!
This is working:
SELECT members.*, count(comments.rel) as count
FROM members, comments
WHERE members.userid=comments.userid
group by members.userid

Is there a disadvantage to using "USING" instead of "ON" in MySQL?

Two snippets of MySQL:
SELECT * FROM annoyingly_long_left_hand_table
LEFT JOIN annoyingly_long_right_hand_table
ON annoyingly_long_left_hand_table.id = annoyingly_long_right_hand_table.id;
vs
SELECT * FROM annoyingly_long_left_hand_table
LEFT JOIN annoyingly_long_right_hand_table
USING (id);
Given that both tables have an id field, is there any disadvantage to using the second version. It isn't just laziness - the version with USING seems far clearer to me.
(Please don't mention aliasing - I want to know if there is any reason to favour one conditional structure over the other)
There is a small functional difference between the two, in that instead of getting 2 ID columns, you only get one.
SELECT * FROM foo JOIN bar ON ( foo.id == bar.id )
id , fooname, id, barname
SELECT * FROM foo JOIN bar USING ( id )
id, fooname, barname
So there are at least some additional knowledge requirements for users utilising this syntax, http://dev.mysql.com/doc/refman/5.0/en/join.html
USING is a bit less flexible than a general-purpose ON clause:
The column(s) in both tables must have the same name.
The comparison must be equality.
No other table in the query can have a column of the same name.