update row without deleting previous values in mysql - php

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

Related

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

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

mysql query need to be optimized

I have a query which give result like
id | productid | userid | coinsid
1 | 2 | 2 | 5
3 | 2 | 2 | 6
4 | 2 | 3 | 7
5 | 2 | 4 | 8
6 | 2 | 3 | 9
This is result for specific productid. Now i have to update the balance in user table by adding $1 to all the users in above result, but if userid is twice, i need to add $1 twice to the balance of that specific user. So in the above case $1 twice added to userid=2 balance and userid=3 balance.
The simple way is to count records for every distinct userid and run queries as many time as we have users in foreach loop. But i am looking for some optimize way. Please suggest any. Thanks
One approach:
UPDATE user_table u
JOIN ( SELECT q.userid
, SUM(1.00) AS deposit
FROM (
-- original OP query goes here
) q
GROUP BY q.userid
) r
ON r.userid = u.userid
SET u.balance = u.balance + r.deposit
We use the original OP query that returns the resultset displayed, and make that an inline view (aliased in the query above as q).
From that, we query a distinct list of userid, and the number of times that userid appears in the resultset. That gives us the username and a deposit amount (1 dollar for each time the userid appears) (some databases might want us to specify the value as 1.0 rather than 1, to make sure it was decimal. I think the SUM is more representative of what we are trying to accomplish.)
We join that inline view (r) to the user table, and add the deposit amount to the current balance, for that user (assuming the balance is stored as decimal dollars (1.00 = one dollar)
To testing, convert the UPDATE into a SELECT statement:
remove the "SET" clause
add an "ORDER BY" clause (optional) to make the results determinate
remove the "UPDATE" keyword and replace it
with:
SELECT r.userid
, r.deposit
, u.balance AS old_balance
, u.balance + r.deposit AS new_balance
, u.userid
FROM
Full select:
SELECT r.userid
, r.deposit
, u.balance AS old_balance
, u.balance + r.deposit AS new_balance
, u.userid
FROM user_table u
JOIN ( SELECT q.userid
, SUM(1.00) AS deposit
FROM (
-- original OP query goes here
) q
GROUP BY q.userid
) r
ON r.userid = u.userid
NOTE There is no WHERE clause, the JOIN predicates (in the ON clause) is what determines which rows are selected/affected in the user table.
Assuming you have no duplicate user ids in your balance table, maybe something like this would work:
update balance_table set balance_table.balance = (select count(*) from users_table where users_table.user_id = balance_table.user_id) * 1;
I haven't tried this query against a mysql database as I am more familiar with plsql, but wouldn't something like this work ?
The correlated subquery in the other answer will work, but an INNER JOIN will usually be more efficient. Try something like this; you'll of course need to supply the table and column names.
UPDATE myTable
INNER JOIN (
SELECT userid, count(*) AS AmountToAdd
FROM users
GROUP BY userid
) UserCounts ON myTable.userid = UserCounts.userid
SET balance = balance + UserCounts.AmountToAdd
select count(*), userid from yourTable group by userid
If I do understand your question.

Delete values with two duplicate values inrespective of which column they are in

I have a mysql table which looks something like this:
id_one id_two
1 2
2 1
3 2
2 3
4 5
5 4
I want to delete rows with two duplicate values inrespective of which columns they are in so the example would look like this:
id_one id_two
1 2
3 2
5 4
There are over 12 million rows in total. Any ideas on how I should do this?
Php or mysql query would be preferred.
DELETE a
FROM table1 a
LEFT JOIN
(
select id_one, id_two
from Table1
GROUP BY least(id_one, id_two), greatest(id_one, id_two)
) b ON a.id_one = b.id_one AND a.id_two = b.id_two
WHERE b.id_two IS NULL
SQLFiddle Demo
I would advise a 2-step approach:
Make id_one always the smaller value, i.e., if id_one is larger than id_two then swap their values - consider something like this (taken from here):
UPDATE tablename
SET id_one = (#temp:=id_one), id_one = id_two, id_two = #temp
WHERE id_one > id_two
Remove the duplicates as described here:
DELETE tablename FROM tablename INNER JOIN
(SELECT min(primary_key) AS min_id, id_one, id_two FROM tablename
GROUP BY id_one, id_two
HAVING count(1) > 1) AS d
ON (d.id_one = tablename.id_one
AND d.id_two = tablename.id_two
AND d.min_id <> tablename.primary_key)
(I assume that you will have a primary key on a table that holds 12 million entries.)
Not tested, so please backup your data!
DELETE FROM ztable zt
WHERE zt.id_one > zt.id_two
AND EXISTS (
SELECT *
FROM ztable tx
WHERE tx.id_one = zt.id_two
AND tx.id_two = zt.id_one
)
;
won't work in mysql, because in mysql you cannot reference the table being updated or deleted.
Since you want to make a backup copy anyway, you could use that instead in the EXISTS subquery:
CREATE table safetable AS (SELECT * from ztable);
DELETE FROM ztable zt
WHERE zt.id_one > zt.id_two
AND EXISTS (
SELECT *
FROM safetable tx
WHERE tx.id_one = zt.id_two
AND tx.id_two = zt.id_one
);

trying to output the correct value from SQL query from comparing a different table

I'm very new with SQL and need assistance on how I can accomplish this task using the correct query.
I have 2 tables that I need to use. Table "TB1" has:
id Name
1 bob
2 blow
3 joe
table "TB2" has:
compid property
1 bob
2 blow
I am trying to get which compid is missing in "TB2" and insert it from "TB1"
the query I am doing is:
SELECT id, name from TB1, TB2 where id <> compid
what I get is 2 ouputs of Id 1, and 2, and 3 outputs from id 3. by using php:
for($i=0;$i <= mysql_num_rows($comp)-1; $i++)
{
echo mysql_result($comp, $i, 0)."<br>";
}
and I expected the ouput 3 but instead got this:
1
1
2
2
3
3
3
I understand its comparing all the rows within the table but is there a way to achieve what I am looking for?
Thanks for your time.
You are performing an implicit Cartesian JOIN which results in every row against every other row. You need to specify what attribute JOINs the two tables.
Using implicit syntax (not recommended):
SELECT id, name
FROM TB1, TB2
WHERE id <> compid
AND TB1.Name = TB2.property <-- Column join
Using explicit syntax:
SELECT id, name
FROM TB1
JOIN TB2
ON TB2.property = TB1.Name <-- Column join
WHERE id <> compid
To accomplish your goal you would need something along the lines of:
SELECT TB1.id, TB1.name
FROM TB1
LEFT JOIN TB2
ON TB2.property = TB1.Name
WHERE TB2.compid IS NULL
See it in action
It's best practice to always alias the columns you select to prevent ambiguity.
To select it you can do:
SELECT *
FROM TB1
WHERE id NOT IN (
SELECT compid
FROM TB2
);

condition update cells within the same column

I need to update cells within a specific column based upon ids in another column. The column names are Prod_ID, Lang_ID and Descr:
Prod_ID | Lang_ID | Descr
--------+---------+------
A101 | 1 | TextA
A101 | 2 | TextB
A101 | 3 | TextC
For a group of rows with the same Prod_ID, I need to replace all subsequent descriptions (Descr column) with the description of the first row. The row with the correct description has always Lang_ID = 1. Also, the table may not be sorted by Lang_ID.
Example: TextA (Lang_ID = 1) should replace TextB and TextC because the Prod_IDs of the rows match.
You mentioned in a comment elsewhere that the "master" lang_id is always 1. That simplifies things greatly, and you can do this with a simple self-join (no subqueries :-)
This query selects all lang_1 rows, then joins them with all non-lang_1 rows of the same prod_id and updates those.
If Lang_ID=1 is always the "first"
UPDATE products
LEFT JOIN products as duplicates
ON products.Prod_ID=duplicates.Prod_ID
AND duplicates.Lang_ID != 1
SET duplicates.Descr = products.Descr
WHERE products.Lang_ID = 1
edit: If Lang_ID=1 may not be the "first"
you can join the table to itself via a an intermediate join which finds the lowest Lang_ID for that row. I have called the intermediate-join "lang_finder".
UPDATE products
LEFT JOIN (SELECT Prod_ID, MIN(Lang_ID) as Lang_ID FROM products GROUP BY Prod_ID) as lang_finder
ON products.prod_id=lang_finder.prod_id
LEFT JOIN products as cannonical_lang
ON products.Prod_ID = cannonical_lang.Prod_ID
AND lang_finder.Lang_ID = cannonical_lang.Lang_ID
SET products.Descr = cannonical_lang.Descr
Note that while it does use a subquery, it does not nest them. The subquery essentially just adds a column to the products table (virtually) with the value of the lowest Lang_ID, which then allows a self-join to match on that. So if there were a product with Lang_ID 3, 4, & 5, this would set the Descr on all of them to whatever was set for Lang_ID 3.
How about this?
UPDATE myTable dt1, myTable dt2
SET dt1.Descr = dt2.Descr
WHERE dt1.Prod_ID=dt2.Prod_ID;
Demo at sqlfiddle
Assuming that the correct description is always in the row of a group of rows with the same Prod_ID where Lang_ID has the smallest value, this MySQL query should work:
UPDATE your_table AS t1
JOIN (
SELECT Prod_ID, Descr
FROM (
SELECT *
FROM your_table
ORDER BY Lang_ID
) AS t3
GROUP BY Prod_ID
) AS t2
ON t1.Prod_ID = t2.Prod_ID
SET t1.Descr = t2.Descr;
The above can be used e.g. if Lang_ID is a primary or unique key. It also works if the corresponding Lang_ID has always the same minimum value (e.g. = 1) but in that case much less complex queries like this one are possible.

Categories