I have a table A with duplicate data and I would like to normalize it. But there is another table B which refers to table A ids. There is no real foreign key. It is only the fact. I would like to create temp. table C and fill it by use ON DUPLICATE KEY UPDATE to remove duplicities from table A. But so I lose some ids which make references to from table B to table A.
I would like to write a function which will be called like
ON DUPLICATE KEY UPDATE id = setNewId(`id`, VALUES(`id`))
Is it possible to make function setNewId() which will update table C.id and B.id to new value on dulicate key update?
This will create C with all the duplicate values of unique_field removed.
CREATE TABLE C LIKE A;
ALTER TABLE C ADD UNIQUE INDEX (unique_field);
INSERT IGNORE INTO C
SELECT * FROM A;
After you create C, you can use a join between A and C to find the corresponding ID, and use that to update B.
UPDATE B
JOIN A ON B.foreign_key = A.id
JOIN C ON C.unique_field = A.unique_field AND C.id != A.id
SET B.foreign_key = C.id;
After that's done, drop A and rename C to A.
Related
I was asked to update a SQL Server table's primary key column, the column already has values. On inner joining with few other tables, I had to update the PK column values from another table. It's failing to do so due to duplicates, inserting value 435 to 2 or more PK column.
Any suggestion how it can be done?
UPDATE t
SET t.ID = c.NewID
FROM Table1 t
INNER JOIN Table2 p ON p.ID = t.ID
LEFT OUTER JOIN Table3 c ON c.ID = t.ID
WHERE c.status = 'Y'
Let's say your PK is called A, so:
create a new column called B
update table set B = A
do the changes you need to B
go through all the tables you have FK to your table; drop them, and make sure to reflect the data changes;
drop the PK on A
recreate it on B
recreate all the FKs you dropped 3 steps ago on B
Simple :)
I'm joking, as you can see it is very complicated and error prone. You shouldn't have to worry about your PKs values - if you are there is something wrong in your design
I created a index called abc on a table called table with a PRIMARY KEY called id and three others INT columns a, b and c that can be NULL.
Now I need this index to be UNIQUE, so I tried :
ALTER TABLE table DROP INDEX abc, ADD UNIQUE abc (a, b, c);
But I have duplicates, so MySQL answers :
#1062 - Duplicate entry '1-2-3' for key 'abc'
I probably have a lot of those duplicates, so I'm looking for an easy way to search & destroy them all. My first guess has been :
SELECT * FROM table GROUP BY abc
But sadly it seems that you can't group by indexes.
Is there an easy way to find those duplicates, keep one line of each duplicate and delete the others ?
EDIT :
table as an id field that is a PRIMARY KEY
a, b and c are all INT and can be NULL
No need to eliminate duplicates first, just use the IGNORE option for ALTER TABLE to do exactly what you want;
ALTER IGNORE TABLE table DROP INDEX abc, ADD UNIQUE abc (a, b, c);
An SQLfiddle to test with.
If IGNORE is not specified, the copy is aborted and rolled back if duplicate-key errors occur. If IGNORE is specified, only one row is used of rows with duplicates on a unique key. The other conflicting rows are deleted.
...and always remember to back up your data before running potentially destructive SQL from random people on the Internet.
SELECT a,b,c
FROM table
GROUP BY a,b,c
HAVING count(*)>1
try this to find dupes
Select a, b, c
From table
group By a, b, c
Having Count(*) > 1
If there is already a unique key column (say its pkColumn) on this table,
you can do this to delete extra dupes.
Delete table
From table t
Where pkColumn <>
(Select Min(pkColumn)
From table
where a = t.a
and b = t.b
and c = t.c)
I'm guessing you have several records that aren't in this situation.
To avoid losing data
CREATE table duplicates SELECT MIN(id) as id, a, b, c, COUNT(1) as nduplicates
FROM yourtable
GROUP BY a,b,c
HAVING COUNT(1)>1;
UPDATE yourtable t, duplicates d
SET t.a='toDelete(or some value that you can easy identify from the rest)'
WHERE d.a=t.a and d.b=t.b and d.c=t.c
and d.id!=t.id;
DELETE FROM yourtable WHERE a='toDelete';
and then drop duplicates table.
Is there some sort of magical SQL statement to delete a row and all its dependents (linked by foreign key constraints) WITHOUT altering the table to add ON DELETE CASCADE or deleting each dependent row manually?
I am fantasizing something such as DELETE FROM `table_a` WHERE `id` = 1 ON DELETE CASCADE; but I can't seem to find anything to this effect in the doc # http://dev.mysql.com/doc/refman/5.5/en/delete.html
I don't want to ALTER the table to change the constraints for just a one time operation and then revert it back using another ALTER
I don't want to execute something like DELETE FROM `table_b` WHERE `a_id` = 1; for each table containing a FK to table_a
Using MySQL 5.5 with InnoDB
No, the simple answer is, no, there is no shortcut.
You either write down DELETE statements to delete all the related rows in the related tables or you have defined foreign key constraints with ON DELETE CASCADE.
Note that - as long as there are no circular paths in the foreign key relationships - it is possible to use a single DELETE statement that deletes from multiple tables:
DELETE a, b, c, d
FROM a
LEFT JOIN b ON b.a_id = a.a_id
LEFT JOIN c ON c.a_id = a.a_id
LEFT JOIN d ON d.b_id = b.b_id
WHERE
a.a_id = 1 ;
There are 2 tables, spawnlist and npc, and I need to delete data from spawnlsit.
npc_templateid = n.idTemplate is the only thing that "connect" the tables.
I have tried this script but it doesn't work.
I have tried this:
DELETE s FROM spawnlist s
INNER JOIN npc n ON s.npc_templateid = n.idTemplate
WHERE (n.type = "monster");
Add .* to s in your first line.
Try:
DELETE s.* FROM spawnlist s
INNER JOIN npc n ON s.npc_templateid = n.idTemplate
WHERE (n.type = "monster");
If the database is InnoDB then it might be a better idea to use foreign keys and cascade on delete, this would do what you want and also result in no redundant data being stored.
For this example however I don't think you need the first s:
DELETE s
FROM spawnlist AS s
INNER JOIN npc AS n ON s.npc_templateid = n.idTemplate
WHERE n.type = "monster";
It might be a better idea to select the rows before deleting so you are sure your deleting what you wish to:
SELECT * FROM spawnlist
INNER JOIN npc ON spawnlist.npc_templateid = npc.idTemplate
WHERE npc.type = "monster";
You can also check the MySQL delete syntax here: http://dev.mysql.com/doc/refman/5.0/en/delete.html
if the database is InnoDB you dont need to do joins in deletion. only
DELETE FROM spawnlist WHERE spawnlist.type = "monster";
can be used to delete the all the records that linked with foreign keys in other tables, to do that you have to first linked your tables in design time.
CREATE TABLE IF NOT EXIST spawnlist (
npc_templateid VARCHAR(20) NOT NULL PRIMARY KEY
)ENGINE=InnoDB;
CREATE TABLE IF NOT EXIST npc (
idTemplate VARCHAR(20) NOT NULL,
FOREIGN KEY (idTemplate) REFERENCES spawnlist(npc_templateid) ON DELETE CASCADE
)ENGINE=InnoDB;
if you uses MyISAM you can delete records joining like this
DELETE a,b
FROM `spawnlist` a
JOIN `npc` b
ON a.`npc_templateid` = b.`idTemplate`
WHERE a.`type` = 'monster';
in first line i have initialized the two temp tables for delet the record,
in second line i have assigned the existance table to both a and b but here i have linked both tables together with join keyword,
and i have matched the primary and foreign key for both tables that make link,
in last line i have filtered the record by field to delete.
i m trying to import records from one table to another table.
i m having tables suppose A,B,C,D.
i m importing records from table A to table B.
Table B has two foreign keys which are primary keys in table C and D.
I m using query as below::
INSERT INTO B(userid,behaviorid,userNid,behaviorNid,timestamp)SELECT userid,behaviorid,userNid,behaviorNid,timestamp FROM A where userNid = ANY (select Nid from C);
but i m getting error as foreign key constraints fails.
How can i solve this.
Thanks in advance.
Well this should check Nid in C for every foreign key in C and append to B.
INSERT INTO B(userid,behaviorid,userNid,behaviorNid,timestamp) SELECT
userid,behaviorid,userNid,behaviorNid,timestamp FROM A LEFT JOIN C on A.foreignkey = C.Nid;
Make sure you try it and comment, if not working