How to concatenate strings into a new column based on GROUP BY - php

I have a similar question to How to use GROUP BY to concatenate strings in MySQL? , however for this example for mytable table
id string aggr
1 A NULL
1 B NULL
2 F NULL
The difference is I need to update the table to get this results:
id string aggr
1 A A|B|
1 B A|B|
5 C C|E|C|
5 E C|E|C|
5 C C|E|C|
2 F F|
As result the same id we have the same newcolumn values.
It is absolutely fine to add a delimiter |at the very end of the string. That way I can even faster count how many "items" are in the newcolumn without adding +1 because of the absense at the very end (just in between). Also I won't care about validation (if I have a pipe right before) when appending another part or two into aggr column.
Thank you.

You can try this query :
UPDATE my_table t
SET aggr = (
SELECT * FROM (
SELECT CONCAT(GROUP_CONCAT(t2.string SEPARATOR '|'), '|')
FROM my_table t2
WHERE t2.id = t.id
) AS X
)

You could a group_concat joined on original table
select a.id, a.string , b.aggr
from my_table a
inner join (
select id, group_concat(string SEPARATOR '|') as aggr
from my_table
group by id
) b on a.id = b.id

Related

update row without deleting previous values in mysql

One of my table has a field user_ids and the value of the field like 2,3
group_id| user_ids
--------|------------
1 | 2,3
--------|------------
2 | 5,8
I want to update the field without deleting the current value. For ex. If I need to add 5 for group_id id 1, then 2,3 should be like 2,3,5
I m using this query:
UPDATE users_group SET user_ids = CONCAT( SUBSTRING( user_ids, 1, CHAR_LENGTH( user_ids ) -1 ) , ',5' ) WHERE group_id =1
But it is deleting previous value with comma.
group_id| user_ids
--------|------------
1 | ,5
--------|------------
2 | 5,8
can anyone suggest the right way for this?
Can you not just concatenate it on, rather than trying to split it up first?
UPDATE users_group
SET user_ids = CONCAT_WS(',', user_ids, '5' )
WHERE group_id =1
But this does suggest a badly normalised database design. Generally a comma separated list should instead be stored as rows on another table (ie, one row per value in the list) as suggested by Mark Baker.
EDIT - If you want to only have a single copy of any id in each user_ids field, irrespective of how many times you try to insert it, and you want to be able to add multiple ids at once:-
UPDATE users_group a
INNER JOIN
(
SELECT 3 AS an_id
UNION
SELECT 4
) b
ON FIND_IN_SET(b.an_id, a.user_ids) = 0
SET a.user_ids = CONCAT_WS(',', a.user_ids, b.an_id )
WHERE a.group_id =1
EDIT again - if you have a table of users containing the ids then you can select the ids from that where the id is one of those you want to add.
Something like this.
UPDATE users_group a
INNER JOIN
(
SELECT id
FROM users
WHERE id IN (3, 4)
) b
ON FIND_IN_SET(b.id, a.user_ids) = 0
SET a.user_ids = CONCAT_WS(',', a.user_ids, b.id )
WHERE a.group_id =1
update table1 set name = concat(name, ', ', 5) WHERE group_id =1
Please try this query. It may be useful for you.
UPDATE users_group SET user_ids = CONCAT( user_ids , ',5' ) WHERE group_id =1
Try the below query:
UPDATE users_group
SET user_ids = CONCAT( user_ids , ',5' )
WHERE group_id =1

string split and subquery in mysql

first of all i have 1 table in database.
1)tags :
id name
1 theme1=test1
2 theme1=test2
3 theme1=test3
4 theme2=test1
5 theme2=test2
6 theme2=test3
And i have bunch of id of tags in array. like 1,3.
Now,
1)select name from tags where id=1
result: theme1=test1
(now using wildcard)
2)select id from tags where name like 'theme_test1'
result : 1,4
(here 'theme_test1' need to take from query1)
I am getting output proper but need to use 2 query.I want to do this in single query.
Thanks
SELECT id FROM tags WHERE name LIKE (
SELECT CONCAT(SUBSTRING(name,1,5),'__',SUBSTRING(name,8)) FROM tags WHERE id=1
)
Returns 1,4
But Two queries (or a refactor) might be a better option
If you whant to get the id with the same value you can try this:
SELECT t2.* FROM yourtable t1
JOIN youtable t2 on ON t2.name like concat(substr(t1.name,1,5), '%', substr(t1.name,8))
WHERE t1.id=1;
For performance better use this:
SELECT t.id
FROM r
INNER JOIN r AS t ON t.name LIKE CONCAT('theme_=test', SUBSTRING(r.name,-1))
WHERE r.id = '1'
r is your table in this case.
NOTE: this answer isn't valid in case that you have theme1=test1 and theme1=test10 values.
maybe you can use query :
select id from tags where name = (select name from tags where id = 1 ).
You can try that query.

Sql query to Compare same fields of different rows in the same table in mysql

I'm trying to get the records from "tbl_gig" table while comparing different rows in it.
I tried this but no luck:
SELECT * FROM tbl_gig as t2 INNER JOIN tbl_gig as t3
WHERE t2.gig_city=t3.gig_city
AND t2.artist_id=t3.artist_id
AND t2.partner_id < t3.partner_id
GROUP BY t2.gig_eventDate;
Expected output :
gig_id gig_artist_id gig_partner_id
1 1 1
2/3 1 1/2
4 1 1
Please help on this.
SELECT
GROUP_CONCAT(gig_id SEPARATOR '/') as gig_id,
artist_id ,
GROUP_CONCAT(partner_id SEPARATOR '/') as partner_id
FROM tbl_gig
GROUP BY artist_id

Parent Child Relationships PHP and MYSQL

I have a table like this:
**id name parent_id**
1 X 2
2 Y 2
3 Z 1
4 A 5
5 B 6
6 C 1
I want output look like this:
**name *parent name***
X Y
Y Y
Z X
A B
B C
C X
Is it possible to do it with one query by using JOIN?
You need to perform a self-join:
SELECT child.name AS `name`, parent.name AS `parent name`
FROM my_table AS child JOIN my_table AS parent ON parent.id = child.parent_id
See it on sqlfiddle.
select son.name as name, father.name as parent_name from table_name as son left join table_name as father ON son.parent_id = father.id
Let's say you have 2 tables:
product
product_parent
Then, you run a query like this:
SELECT product.name, product_parent.name
FROM product
INNER JOIN product_parent
ON product.product_parent_id=product_parent.id
You can use JOIN to do this
Example:
SELECT
table.name
, parent.name as parent_name
FROM
table
LEFT JOIN
parent ON parent.parent_id = table.parent_id
WHERE
table.visible = 1
After that you will handle the response from your query in php cycle through returned array of items(array's or object's - depends on what MySQL abstraction you use), save the needed in your own array, or just encoding this array to JSON.
Note: I don't know for what you need this, but it's good idea to include table.id in the result, if you want latter to be able to identify one record.

Need help in optimising query

I have two tables - incoming tours(id,name) and incoming_tours_cities(id_parrent, id_city)
id in first table is unique, and for each unique row from first table there is the list of id_city - s in second table(i.e. id_parrent in second table is equal to id from first table)
For example
incoming_tours
|--id--|------name-----|
|---1--|---first_tour--|
|---2--|--second_tour--|
|---3--|--thirth_tour--|
|---4--|--hourth_tour--|
incoming_tours_cities
|-id_parrent-|-id_city-|
|------1-----|---4-----|
|------1-----|---5-----|
|------1-----|---27----|
|------1-----|---74----|
|------2-----|---1-----|
|------2-----|---5-----|
........................
That means that first_tour has list of cities - ("4","5","27","74")
AND second_tour has list of cities - ("1","5")
Let's assume i have two values - 4 and 74:
Now, i need to get all rows from first table, where my both values are in the list of cities. i.e it must return only the first_tour (because 4 and 74 are in it's list of cities)
So, i wrote the following query
SELECT t.name
FROM `incoming_tours` t
JOIN `incoming_tours_cities` tc0 ON tc0.id_parrent = t.id
AND tc0.id_city = '4'
JOIN `incoming_tours_cities` tc1 ON tc1.id_parrent = t.id
AND tc1.id_city = '74'
And that works fine.
But i generate the query dynamically, and when the count of joins is big (about 15) the query slowing down.
i.e. when i try to run
SELECT t.name
FROM `incoming_tours` t
JOIN `incoming_tours_cities` tc0 ON tc0.id_parrent = t.id
AND tc0.id_city = '4'
JOIN `incoming_tours_cities` tc1 ON tc1.id_parrent = t.id
AND tc1.id_city = '74'
.........................................................
JOIN `incoming_tours_cities` tc15 ON tc15.id_parrent = t.id
AND tc15.id_city = 'some_value'
the query run's in 45s(despite on i set indexes in the tables)
What can i do, to optimaze it?
Thanks much
SELECT t.name
FROM incoming_tours t INNER JOIN
( SELECT id_parrent
FROM incoming_tours_cities
WHERE id IN (4, 74)
GROUP BY id_parrent
HAVING count(id_city) = 2) resultset
ON resultset.id_parrent = t.id
But you need to change number of total cities count.
SELECT name
FROM (
SELECT DISTINCT(incoming_tours.name) AS name,
COUNT(incoming_tours_cities.id_city) AS c
FROM incoming_tours
JOIN incoming_tours_cities
ON incoming_tours.id=incoming_tours_cities.id_parrent
WHERE incoming_tours_cities.id_city IN(4,74)
HAVING c=2
) t1;
You will have to change c=2 to whatever the count of id_city you are searching is, but since you generate the query dynamically, that shouldn't be a problem.
I'm pretty sure this works, but a lot less sure that it is optimal.
SELECT * FROM incoming_tours
WHERE
id IN (SELECT id_parrent FROM incoming_tours_cities WHERE id_city=4)
AND id IN (SELECT id_parrent FROM incoming_tours_cities WHERE id_city=74)
...
AND id IN (SELECT id_parrent FROM incoming_tours_cities WHERE id_city=some_value)
Just an hint.
If you use the IN operator in a WHERE clause, you can hope that the short-circuit of operator AND may remove unnecessary JOINs during the execution for the tours that do not respect the constraint.
Seems like an odd way to do that query, here
SELECT t.name FROM `incoming_tours` as t WHERE t.id IN (SELECT id_parrent FROM `incoming_tours_cities` as tc WHERE tc.id_city IN ('4','74'));
I think that does it, but not tested...
EDIT: Added table alias to sub-query
I've written this query using CTE's and it includes the test data in the query. You'll need to modify it so that it queries the real tables instead. Not sure how it performs on a large dataset...
Declare #numCities int = 2
;with incoming_tours(id, name) AS
(
select 1, 'first_tour' union all
select 2, 'second_tour' union all
select 3, 'third_tour' union all
select 4, 'fourth_tour'
)
, incoming_tours_cities(id_parent, id_city) AS
(
select 1, 4 union all
select 1, 5 union all
select 1, 27 union all
select 1, 74 union all
select 2, 1 union all
select 2, 5
)
, cityIds(id_city) AS
(
select 4
union all select 5
/* Add all city ids you need to check in this table */
)
, common_cities(id_city, tour_id, tour_name) AS
(
select c.id_city, it.id, it.name
from cityIds C, Incoming_tours_cities tc, incoming_tours it
where C.id_city = tc.id_city
and tc.id_parent = it.id
)
, tours_with_all_cities(id_city) As
(
select tour_id from common_cities
group by tour_id
having COUNT(id_city) = #numCities
)
select it.name from incoming_tours it, tours_with_all_cities tic
where it.id = tic.id_city

Categories