Invalid use of group function (group_concat and MySQL) - mysql

I have a problem to implement this:
UPDATE users
INNER JOIN relations_colors ON (relations_colors.user_id = users.id)
INNER JOIN colors ON (colors.id = relations_colors.color_id)
SET search_cache = GROUP_CONCAT( colors.name SEPARATOR " ")
phpmyadmin says: "#1111 - Invalid use of group function", how can I fix?

I think something like this will perform the update operation you are looking for:
UPDATE users u
JOIN ( SELECT r.user_id
, GROUP_CONCAT(c.name SEPARATOR ' ') AS search_cache
FROM relations_colors r
JOIN colors c ON c.id = r.color_id
GROUP BY r.user_id
) s
ON u.id = s.user_id
SET u.search_cache = s.search_cache
Note that this will update only rows in the users table that have a matching row from relations_colors/colors.
To update ALL rows of users, you'd want to include the LEFT keyword before the JOIN keyword to get an "outer join"; that would set the search_cache column to NULL for users that didn't have any matching rows.
To make the result more deterministic, we'd typically include an ORDER BY clause inside the GROUP_CONCAT function, for example:
GROUP_CONCAT(c.name SEPARATOR ' ' ORDER BY c.id)

Related

MySQL query with GROUP BY and JOIN

Good afternoon,
I'm trying to get some information from my MySQL database and I'm having problems because I'm not able to have the information needed. I have tried a lot of different approaches and none of them have worked. I hope you can find something because I'm very close to find the solution but something is missing:
MySQL query:
SELECT b.id, b.tipo_perfil, round(avg(b.edad)), COUNT(c.zona), c.zona
FROM analizador_datos_usuario AS a
INNER JOIN analizador_datos_perfil AS b ON (a.id_usuario = b.id_perfil)
INNER JOIN analizador_datos_perfil_historial AS c ON (b.id = c.id_perfil)
WHERE a.id_usuario=21
GROUP BY b.tipo_perfil, c.zona
ORDER BY b.tipo_perfil ASC, count(c.zona) DESC
This query gives me the following information:
Table (in red it's what I need):
Kind regards,
try that :
SELECT b.tipo_perfil, round(avg(b.edad)), COUNT(distinct c.zona), group_concat(distinct b.id separator ' ') as id_list, group_concat(distinct c.zona separator ' ') as zona_list
FROM analizador_datos_usuario AS a
INNER JOIN analizador_datos_perfil AS b ON (a.id_usuario = b.id_perfil)
INNER JOIN analizador_datos_perfil_historial AS c ON (b.id = c.id_perfil)
WHERE a.id_usuario=21
GROUP BY b.tipo_perfil
ORDER BY b.tipo_perfil ASC, count(distinct c.zona) DESC
I think you are getting result what is displayed and you want result which is in red colour.
Try this modified query:-
SELECT b.id, b.tipo_perfil, round(avg(b.edad)), COUNT(c.zona) counted_zone, c.zona
FROM analizador_datos_usuario AS a
INNER JOIN analizador_datos_perfil AS b ON (a.id_usuario = b.id_perfil)
INNER JOIN analizador_datos_perfil_historial AS c ON (b.id = c.id_perfil)
WHERE a.id_usuario=21
GROUP BY b.tipo_perfil, c.zona
Having MAX(counted_zone)
ORDER BY b.tipo_perfil ASC, counted_zone DESC

MySQL AS in JOIN statement

I have a table (edu_posts) which contains posts. The field "post_receiver" usually contains a user_id, but sometimes it may contain an event ID (syntax: event-ID) and I have created a statement like this:
SELECT
p.*,
u.firstname AS post_author_firstname,
u.lastname AS post_author_lastname,
u3.firstname AS receiver_firstname,
u3.lastname AS receiver_lastname,
pl.like_author AS user_likes,
CASE
WHEN p.post_receiver REGEXP '^[a-z]'
THEN
SUBSTRING_INDEX(
SUBSTRING_INDEX(p.post_receiver, '-', 2),
'-',
- 1
)
END
AS event_id,
e.event_name AS event_name
FROM
edu_posts p
LEFT JOIN edu_users u ON u.user_id = p.post_author
LEFT JOIN edu_users u3 ON u3.user_id = p.post_receiver
LEFT JOIN edu_likes pl ON pl.like_entity = p.post_id
LEFT JOIN edu_events e ON e.event_id = event_id
AND pl.like_author = 1
GROUP BY
p.post_id,
pl.like_id
ORDER BY
p.post_date DESC
Have a look at CASE and below in the SELECT statement, and the last LEFT JOIN.
I figured I cannot retrieve data from "event_id" i created in the SELECT statement. So what could I do to LEFT JOIN based on EVENT_ID's value?
Maybe this whole progress is too complicated, and instead it would be better and more effective to make a new MySQL call in the PHP code, if post_receiver is equal to: event-someID?
What are your thoughts? Thanks in advance!

MySQL / PHP - 2 different arguments for 1 table

I have the following SQL:
$queryString = "
SELECT
iR.lastModified,
d.*,
c2.title as stakeholderTitle,
u.username as authorUsername,
c.title as authorContactName,
GROUP_CONCAT(iR.stakeholderRef) AS participants
FROM
informationRelationships iR,
contacts c2
INNER JOIN
debriefs d ON
d.id = iR.linkId
LEFT JOIN
users u ON
u.id = iR.author
LEFT JOIN
contacts c ON
c.ref = u.contactId
LEFT JOIN
debriefs d2 ON
d2.stakeholder = c2.ref
WHERE
(
iR.clientRef = '$clientRef' OR
iR.contactRef = '$contactRef'
)
AND
iR.projectRef = '$projectRef' AND
iR.type = 'Debrief'
GROUP BY
iR.linkId
ORDER BY
d.dateOfEngagement
";
notice how I require 2 different bits of data for the the contacts table.
So at one point, I need to match
c.ref = u.contactId
This will return one bit of information
but I also need a completely different grouping:
d2.stakeholder = c2.ref
Problem is that the title is the column i'm interested in for both:
c2.title as stakeholderTitle,
...
c.title as authorContactName
How do I go about doing this?
My current try is returning:
Error: Unknown column 'iR.linkId' in 'on clause'
I'm not sure I really understand what is happening here:
how to join two tables on common attributes in mysql and php?
EDIT::::---ANSWERED--zerkms
$queryString = "
SELECT
iR.lastModified,
d.*,
c2.title as stakeholderTitle,
u.username as authorUsername,
c.title as authorContactName,
GROUP_CONCAT(iR.stakeholderRef) AS participants
FROM
informationRelationships iR
INNER JOIN
debriefs d ON
d.id = iR.linkId
INNER JOIN
contacts c2 ON
d.stakeholder = c2.ref
LEFT JOIN
users u ON
u.id = iR.author
LEFT JOIN
contacts c ON
c.ref = u.contactId
WHERE
(
iR.clientRef = '$clientRef' OR
iR.contactRef = '$contactRef'
)
AND
iR.projectRef = '$projectRef' AND
iR.type = 'Debrief'
GROUP BY
iR.linkId
ORDER BY
d.dateOfEngagement
";
By re-ordering my query I have managed to get both columns in... Thanks zerkms!
You cannot mix implicit joins and explicit joins in a single query in mysql.
So
FROM informationRelationships iR,
contacts c2
should be rewritten to
FROM informationRelationships iR
INNER JOIN contacts c2 ON ...
Do not use cartesian product and joins in the same query (not subquery), here, use only joins (CROSS JOIN is the same as cartesian product).

MySql on what cols should I put indexes?

I have this query:
SELECT Concat(f.name, ' ', f.parent_names) AS FullName,
stts.name AS 'Status',
u.name AS Unit,
city.name AS City,
(SELECT Group_concat(c.mobile1)
FROM contacts c
WHERE c.id = f.husband_id
OR c.id = f.wife_id) AS MobilePhones,
f.phone AS HomePhone,
f.contact_initiation_date AS InitDate,
f.status_change_date AS StatusChangeDate,
cmt.created_at AS CommentDate,
cmt.comment AS LastComment,
f.reconnection_date AS ReconnectionDate,
(SELECT Group_concat(t.name, ' ')
FROM taggings tgs
JOIN tags t
ON tgs.tag_id = t.id
WHERE tgs.taggable_type = 'family'
AND tgs.taggable_id = f.id) AS HandlingStatus
FROM families f
JOIN categories stts
ON f.family_status_cat_id = stts.id
JOIN units u
ON f.unit_id = u.id
JOIN categories city
ON f.main_city_cat_id = city.id
LEFT JOIN comments cmt
ON f.last_comment_id = cmt.id
WHERE 1 = 0
OR ( u.is_busy = 1 )
OR ( f.family_status_cat_id = 1423 )
OR ( f.family_status_cat_id = 1422
AND f.status_change_date BETWEEN '2011-03-21' AND '2012-03-13' )
My problem is very specific. It is regarding the line:
SELECT GROUP_CONCAT( c.mobile1 )
FROM contacts c
WHERE c.id = f.husband_id
OR c.id = f.wife_id
) AS MobilePhones
When I use EXPLAIN, it seems that this query is bad. I get for this table (c = contacts): 38307 rows.
On what columns should I put the index according to the query?
I tried mobile1 - but no improvement (BTW - family_id is indexed in the contacts table).
I attach the image of the explain result:
Or maybe someone can help me optimize the query...
Any column you'll be searching on, to speed up the process. Keep in mind that keys are already indexed.
Well, it seems that using the GROUP_CONCAT is the problem.
I just seperated the wife and husband mobile to be 2 different columns.
First, I thought that using the GROUP_CONCAT will be faster, but it proved to be VERY WRONG.
Just out of my curiosity, what is the performance of the query
SELECT GROUP_CONCAT( c.mobile1 )
FROM contacts c
WHERE c.id IN(f.husband_id, f.wife_id)
) AS MobilePhones

Updating users table from complex SQL query, users.id not recognised?

So the other day, I asked this question about how to combine three complex queries and found a way to do it. Now I'm trying to use those queries to update a field in the users table and can't find a way to make it work. Here's the query:
update users set field_sum =(
select sum(field_sum) from (
select sum(field_one) as field_sum
from t_a join t_b on (t_a.bid = t_b.id) where t_b.user_id=users.id
union all
select sum(field_two) as field_sum
from t_c join t_d on (t_c.did = t_d.id) where t_d.user_id=users.id
union all
select sum(field_three) as field_sum
from t_e where t_e.user_id=users.id
) as field_sumT
)
When I try to run it, I get the following error: ERROR 1054 (42S22): Unknown column 'users.id' in 'where clause'. When I try removing the .user_id=users.id bit from each where clause, it will run but ends up with the total sum of field_sum, not just the field_sum for that user. Is there any way to accomplish this?
Use:
UPDATE USERS u
LEFT JOIN (SELECT t_b.user_id,
SUM(field_one) as field_sum
FROM t_a
JOIN t_b on t_a.bid = t_b.id
GROUP BY t_b.user_id) a ON a.user_id = u.id
LEFT JOIN (SELECT t_d.user_id,
SUM(field_two) as field_sum
FROM t_c
JOIN t_d on t_c.did = t_d.id
GROUP BY t_d.user_id) b ON b.user_id = u.id
LEFT JOIN (SELECT t_e.user_id,
SUM(field_three) as field_sum
from t_e
GROUP BY t_e.user_id) c ON c.user_id = u.id
SET field_num = COALESCE(a.field_sum, 0) + COALESCE(b.field_sum, 0) + COALESCE(c.field_sum, 0)
Caveat
This will set any users with no records in the supporting rows to have a field_sum value of zero. Do you only want to update those with a record in at least one of those tables?