I need an update statement to resolve some issues with duplicates in a table on MySQL. The table structure is shown below. I need a MySQL statement that will set the value of duplicate as NULL except the first one, i.e the one with the lowest id. Here the id is the primary key.
This is an example of what I have:
id name
1 foo
2 foo
3 bar
4 NULL
5 NULL
6 foo
7 bar
This is the desired result:
id name
1 foo
2 NULL
3 bar
4 NULL
5 NULL
6 NULL
7 NULL
The table has other columns with useful information. Hence, the row can't just simply be deleted.
I would write this as:
UPDATE t JOIN
(SELECT name, MIN(id) as min_id
FROM t
GROUP BY name
) tt
ON t.name = tt.name and t.id > tt.min_id
SET t.name = NULL;
I think the logic is easier to follow using JOIN. Basically, it says to find the minimum id for each name. Then set all other rows for the same name to NULL.
Your UPDATE query can include a JOIN.
e.g. join the minimum id for each name and only update where the id is not the minimum.
UPDATE
t
LEFT OUTER JOIN (
SELECT
MIN(id) AS id
FROM
t
GROUP BY
name
) t1 ON t.id = t1.id
SET
t.name = NULL
WHERE
t1.id IS NULL
DB Fiddle
UPDATE t JOIN
(SELECT name, MIN(id) as min_id
FROM t
WHERE name IS NOT NULL
GROUP BY name
HAVING COUNT(*) > 1
) tt
ON t.name = tt.name and t.id > tt.min_id
SET t.name = NULL;
Related
I have the table contacts which contains duplicate records:
id name is_contacted created_at
I need to delete duplicates, but keep the first record(among the duplicates for each name) where is_contacted=1.
If among the record duplicates there are no records where is_contacted=1, just keep the first one.
This is what I have so far:
DELETE c1 FROM contacts c1
INNER JOIN contacts c2
WHERE
c1.id > c2.id AND
c1.name = c2.name;
Assuming that is_contacted's data type is BOOLEAN and id is the primary key of the table and this is the column that defines the order and which row should be considered first, use ROW_NUMBER window function to rank the rows of each name:
WITH cte AS (
SELECT *, ROW_NUMBER() OVER (PARTITION BY name ORDER BY is_contacted DESC, id) rn
FROM contacts
)
DELETE t
FROM contacts t INNER JOIN cte c
ON c.id = t.id
WHERE c.rn > 1;
ORDER BY is_contacted DESC, id returns the rows with is_contacted = 1 at the top (if they exist).
For versions of MySql prior to 8.0, without support of CTEs and winow functions, use a join of the table to a query that uses aggregation to get the id of the row that you want to keep:
DELETE t
FROM contacts t
INNER JOIN (
SELECT name,
COALESCE(MIN(CASE WHEN is_contacted THEN id END), MIN(id)) id
FROM contacts
GROUP BY name
) c ON c.name = t.name AND c.id <> t.id;
Below query will filter only records what you want.
You didn't mention what is primary key in your table, so I don't know how to join this back 1:1 with your whole table.
But if you are not able to determine primary key, they you can create new table using this query, drop original one and rename it to original one.
SELECT * FROM
(
SELECT *,
ROW_NUMBER(PARTITION BY name ORDER BY CASE WHEN is_contacted = 1 THEN -999999 else is_contacted END ) AS RN_
from contacts
) c
WHERE c.RN_ = 1
I can't find the answer to the current question with my versions of SQL so hopefully someone can help me out.
I am using MySQL with SQLPro as the client or I can use PostgreSQL pgAdmin 4.
scenario I am trying to update a null value with the previous not null value.
here is my table:
primary_id name address id
1 bob 123 main 100
2 jane 123 main NULL
3 mike 217 2nd 200
4 jeff 217 2nd NULL
How can I populate the null values with the not null values so that the address/ID grouping remain constant down my columns?
thanks!!!
If you want to update the table, this will work in Postgres:
update t
set id = (select t2.id
from t t2
where t2.address = t.address and t2.id is not null
fetch first 1 row only
)
where id is null;
In MySQL, this will work:
update t join
(select address, max(id) as max_id
from t
group by address
) tt
on t.address = tt.address
set t.id = tt.max_id
where t.id is null;
You can try updating the table with itself. I inserted your table into a users table I created in postgres:
UPDATE users
SET
id = _users.id
FROM
(
SELECT DISTINCT
address,
id
FROM users
WHERE id IS NOT NULL
GROUP BY
address,
id
) _users
WHERE
_users.address = users.address
AND users.id IS NULL;
So the idea is that I grab all all the non-null address and id groups (assuming address is always paired with the same id. I call this _users.
Match _users.address with your original users.address. Make sure that you are only updating the NULL users.id.
I am trying to create a query to mass update a value (default_on) where the id_product is distinct.
UPDATE ps_product_attribute_shop
SET default_on=1
FROM ps_product_attribute_shop
JOIN
(
SELECT id_product
FROM 'ps_product_attribute_shop'
GROUP BY id_product
HAVING COUNT(*) = 1
) AS FIRST_PRODUCT
ON FIRST.id_product = ps_product_attribute_shop.id_product
My db looks like:
id | product_id | default_on
___________________________
1 | 11238 | NULL
2 | 11238 | NULL
3 | 11238 | NULL
4 | 11252 | NULL
So as my above example 11238 can be found multiple times and 11252 one time. So i need to update only one record from all of the 11238`s found and the record 11252 also
But is not working :(
Your syntax is off. It should be this:
UPDATE ps_product_attribute_shop t1
INNER JOIN
(
SELECT id_product, MIN(id) AS min_id
FROM ps_product_attribute_shop
GROUP BY id_product
) t2
ON t1.id_product = t2.id_product AND
t1.id = t2.min_id
SET t1.default_on = 1
In addition to having the commands in the wrong order, you also put the table names in single quotes inside the subquery. Single quotes in MySQL denotes a string literal.
Update:
To handle your revealed update logic, we can arbitrarily update the minimum id record for each product group. The subquery in the above update identifies the records which should be updated.
Try this:
UPDATE ps_product_attribute_shop as p
SET default_on=1
WHERE p.id in (
SELECT MIN(id)
FROM ps_product_attribute_shop
GROUP BY id_product
)
I am using MySQL 5.6.17.
I have a self-referencing table TableA with columns id (PK), title (varchar), type (varchar), parent_id (FK that refers to id of the same table).
The sample data is as below :
id title type parent_id
1 abc G NULL
2 def G NULL
3 xyz G NULL
4 pqr G NULL
5 abc T NULL
6 def T NULL
7 xyz T NULL
8 pqr T NULL
Now, I want each record having type='G' should become the child of the record with type='T' having the same title.
So the resultant table data should be :
id title type parent_id
1 abc G 5
2 def G 6
3 xyz G 7
4 pqr G 8
5 abc T NULL
6 def T NULL
7 xyz T NULL
8 pqr T NULL
I've tried query below :
UPDATE TableA
SET parent_id = (SELECT id FROM ( SELECT id FROM TableA WHERE TYPE='T' ) d)
WHERE TYPE='G';
But it returns
Error Code: 1242
Subquery returns more than 1 row
I also have tried :
UPDATE TableA t1
SET t1.parent_id = t2.newlocalid
INNER JOIN (
SELECT title, id AS newlocalid
FROM TableA t2
WHERE TYPE='T'
) t2 ON t1.title = t2.title
WHERE t1.type='G'
But it also returns the error in Syntax.
Can anyone help me to achieve it?
UPDATE TABLEA a
JOIN TABLEA b ON a.title = b.title and a.type='G'and b.type='T'
SET a.parent_id = b.id
This should work:
SELECT title, id AS newlocalid
INTO #t2
FROM TableA
WHERE TYPE='T'
UPDATE t1
SET t1.parent_id = t2.newlocalid
FROM TableA as t1
INNER JOIN #t2 as t2
ON t1.title = t2.title
WHERE t1.type='G'
Try:
UPDATE TableA a
SET parent_id = (SELECT id FROM TableA ref WHERE TYPE='T' AND ref.title=a.title)
WHERE TYPE='G';
to update the table column first you have to identify which value to set. you can not use multiple values to update the single column in same statement.
change your sql to something like this:
UPDATE TableA
SET parent_id = (SELECT id FROM TableA WHERE TYPE='T' limit 0,1)// i mean make sure that it is returning single record not multiple.or better add some more where condition to get a single and required record without using limit
WHERE TYPE='G';
or to some specific condition like this:
UPDATE TableA
SET parent_id = (SELECT id FROM TableA aa WHERE TYPE='T' and aa.type=TableA.type)
WHERE TYPE='G';
I'm trying to create a query that'll update table_1 where column id_owner has more than 5 rows with the same owner id, it needs to set column "active" to 3 on all rows those users have.
I've tried several different methods and turned up empty with each. Any ideas?
Use this UPDATE query with JOIN to achieve this:
UPDATE table1 t1
JOIN
(
SELECT id_owner
FROM table1
GROUP BY id_owner
HAVING COUNT(*) > 5
) t2
ON t1.id_owner = t2.id_owner
SET t1.active = 3;
See this sample SQLFiddle
You may try this:-
update table_1
set active = 3
where owner_id in
(
select * from
(
select owner_id
from table_1
group by owner_id
having count(*) > 5
) a
)
update table_1
set active = 3
where owner_id in
(
select * from
(
select owner_id
from table_1
group by owner_id
having count(*) > 5
) x
)
SQLFiddle demo