Avoid duplicates on MySQL update - mysql

I have a many-to-many relation table like this
element_a
element_b
1
2
1
3
2
1
2
3
3
1
3
3
I want to replace element_a with id 2 by id 1
UPDATE mytable x
SET x.element_a = 1
WHERE x.element_a = 2;
Since there is an unique index on (element_a, element_b ), this will result with duplicates error.
How can I execute my query without MySQL Error 1062 ?

You can use an update with LEFT JOIN:
UPDATE mytable x
LEFT JOIN mytable t ON t.element_b = x.element_b AND 1 = t.element_a
SET x.element_a = 1
WHERE
x.element_a = 2 AND t.element_a IS NULL
If t.element_a IS NOT NULL then pair element_a, element_b already exists in your table. Thus adding t.element_a IS NULL in the WHERE clause prevents UPDATE in case of duplicates.
Demo here

Related

MySQL - select product_id from 2 different tables and group results

situation:
table 1 - #__virtuemart_products
virtuemart_product_id | product_special
PRODUCTS_IDS | 0 or 1
table 2 - #__virtuemart_product_badges
virtuemart_product_id | product_badge
PRODUCTS_IDS | for this situation code 3
I have a default SQL
SELECT p.`virtuemart_product_id`
FROM `#__virtuemart_products` as p
WHERE p.`product_special` = 1;
results is product IDs like 2,3,225,...
I need modify this SQL syntax for select IDs from 2 different tables and return one column.
If I modify syntax like that:
SELECT p.`virtuemart_product_id`, badges_table.`virtuemart_product_id`
FROM `#__virtuemart_products` as p, `#__virtuemart_product_badges` as badges_table
WHERE p.`product_special` = 1 OR badges_table.`badge` = 3
Result is:
virtuemart_product_id | virtuemart_product_id
1 | 123
1 | 321
1 | 231
....
why is first column 1,1,1,...? here must be product_id, no product_special code
I need group this results into one column virtuemart_product_id
What I doing wrong?
I think what you are looking for is UNION of the IDs fetched from two different tables.
SELECT p.`virtuemart_product_id`, badges_table.`virtuemart_product_id`
FROM `#__virtuemart_products` as p, `#__virtuemart_product_badges` as
badges_table
WHERE p.`product_special` = 1 OR badges_table.`badge` = 3
What the above query is doing is, it is performing a join between the two tables with the condition that product_special should be 1 or badge should be 3. Hence, each row from one table will be joined with each row of the other table where the condition will satisfy.
To get IDs from both the tables you can get the results from each table according to condition and then perform a UNION on them. So for example
(SELECT `virtuemart_product_id` FROM `#__virtuemart_products` WHERE
`product_special` = 1)
UNION
(SELECT `virtuemart_product_id` FROM
`#__virtuemart_product_badges` WHERE `badge` = 3)
I hope this helps.

Update MYSQL Table from multiple rows in another table

I'm trying to update table yy from table xx results by doing sum.
For example (syntax is abstract):
update table_yy
set sum_of_x_and_y = (
(select sum(row_x) from table_xx where class_id=1)
+
(select sum(row_y) from table_xx where class_id=1) )
Table xx
row_id class_id row_x row_y
1 1 4 5
2 1 5 6
3 2 6 7
4 1 7 8
Table yy
class_id sum_of_x_and_y
1 35
2 13
but instead of setting the class_id manually, I would love to do something like inner-join update, but I'm working with 15k+ of records.
Here is a query that should do the job
UPDATE table_yy, (
SELECT class_id, SUM(table_xx.row_x + table_xx.row_y) AS sum_of_x_and_y
FROM table_xx
GROUP BY table_xx.class_id
) AS table_sum
SET table_yy.sum_of_x_and_y = table_sum.sum_of_x_and_y
WHERE table_yy.class_id = table_sum.class_id
Your approach is fine. You just want a correlated subquery:
update table_yy yy
set sum_of_x_and_y = (select sum(xx.row_x) + sum(xx.row_y)
from table_xx xx
where xx.class_id = yy.class_id
);
Under many circumstances, this will have better performance, particularly if you have an index on table_xx(class_id).

Update multiple rows in table based on conditions from another table

Just demo. I have two table
Table a (id, name)
--id---name----
1 John
2 Jack
3 Maria
4 Bill
Table b (id, empid, datewrk)
--id---empid----datewrk----
1 1 2012-12-12
2 2 2012-12-14
3 3 2012-12-16
4 4 2012-12-17
I want update all name = null in table a where date in table b <= '2012-12-14', the result is
--id---name--
1 NULL
2 NULL
I have try code bellow but no work (only work with SELECT statement). I try in MySql Workbench and SQL Server 2012
UPDATE a
SET name = NUll
WHERE id IN (SELECT a.id FROM a
JOIN b ON a.id = b.empid
WHERE b.datewrk <= '2012-12-14');
Thank.
For mysql
UPDATE a
JOIN b ON a.id = b.empid
SET a.name = NUll
WHERE b.datewrk <= '2012-12-14';
You don't need a subquery just join your table put set clause in right place then where clause
Fiddle Demo
Your Update Statement should work, but in order to compare you have to convert '2012-12-14' to date.
UPDATE a
SET name = NULL
WHERE id IN (
SELECT empid FROM b
WHERE datewrk <= STR_TO_DATE('2012-12-14', '%Y-%m-%d'));
Note that in your subquery you don't need table A.
Hope this helps.

Deleting cross referenced data

I have the following MySQL table:
id rid
----- ------
1 2
2 1
2 3
3 2
1 3
3 1
I want to change this so only one row per relation exists.
e.g:
id rid
----- ------
1 2
2 3
1 3
If you always have pairs (as in your example):
delete from table
where id > rid;
This keeps the record where id is smaller.
If there is the possibility that no all pairs exist, then:
delete t
from table t left outer join
(select least(id, rid) as lid, greatest(id, rid) as gid, count(*) as cnt
from table t2
group by least(id, rid), greatest(id, rid)
) t2
on least(t.id, t.rid) = t2.lid and greatest(t.id, t.rid) = gid
where id < rid or t2.cnt = 1;
EDIT (explanation):
How does the second query work? Let me be honest, what I want to write is this:
delete t from table t
where id < rid or
(id > rid and
not exists (select 1 from table t2 where t2.id = t.rid and t2.rid = t.id
);
That is, I want to keep all records where id < rid. But then, I also want to keep all singleton records where rid > id. I don't think MySQL allows the syntax with the where clause.
Instead, the query in the answer counts the number of times that a pair exists, by looking at the smallest value and the largest value. For the data in the question, the result of the subquery is:
id rid cnt
1 2 2
2 3 2
1 3 2
So, all of these would use the id < rid to select the row. If you had one more row, say 4, 1. It would look like:
lid gid cnt
1 2 2
2 3 2
1 3 2
1 4 1
In this case, the first three would take the row with id < rid. But the new row would also be selected because the cnt is 1.
If you had duplicates in the table and a primary key, there would be a slight variation on the query that would do the same thing.

MySQL get parents with the same id and related child

Let say we have an mysql table
Id RelatedId
1 0
2 0
3 1
4 2
5 1
6 2
How can I delete all records with RelatedId=0 and then childs on Id=RelatedId in a single MySQL query?
The alterative to ClaireG's answer is to enforce the relationship with foreign keys set to ON DELETE CASCADE.
You have to check it twice:
DELETE FROM [yourTableName]
WHERE RelatedId = 0
OR (RelatedId in
(select id from [yourTableName] where RelatedId = 0))
Find all the records where relatedID is null, and find all other ids that are related to 0 (in your case [1,2])
seems that works...
DELETE
FROM
delete_table
WHERE
delete_table.RelatedId IN (
select Id from(
SELECT
s1.Id
FROM
delete_table s1
WHERE
s1.RelatedId = 0
) as x
)
OR delete_table.RelatedId = 0;
DELETE TABLENAME
FROM TABLENAME T1
WHERE TABLENAME.ID = T1.RELTED_ID AND T1.RELTED_ID = 0;