Duplicate Primary Key while populating new table from old table - mysql

I've created multiple indexed tables that I want to tie into a new normalized version of an old table. I get everything indexed and the relations set and I get a "Duplicate entry '11' for key 'Primary' " error message.
Here's the code I'm using to populate the new table.
insert into dvdNormal(dvdId, dvdTitle, year, publicRating, dvdStudioId,
dvdStatusId, dvdGenreId)
(
select dvdId, dvdTitle, year, publicRating, studioId, statusId, genreId
from dvd d
join dvdStudio on d.studio = dvdStudio.studioName
join dvdStatus on d.status = dvdStatus.dvdStatus
join dvdGenre on d.genre = dvdGenre.genre);

I'm going to assume you were asking a question, and not just giving a status report.
The behavior you observe is (most likely) due to the insert statement attempting to insert a row that violates a UNIQUE (or PRIMARY KEY) constraint defined on the dvdId column in the target table (the table the statment is inserting rows into.)
And either 1) the dvdId column is not unique in the table it's being retrieved from, or 2) there is more than one "matching" row in one of the other three tables.
For example, if dvdId is a column in dvd, and it's defined as UNIQUE, then case 1) doesn't apply.
But if that row from dvd has more than one "matching" row from one (or more) of the other three tables, then we'd expect the SELECT to generate "duplicate" values for dvdId.
For example, if the genre column is not unique in dvdGenre table, or studioName column is not unique in dvdStudio, we'd expect the query to return multiple copies of the row from dvd. The redundant data (duplicated values) is expected when we "denormalize" data.
If we want to get the table loaded from the query, there's a couple of options.
If we want to store every row returned by the query, we would remove the UNIQUE constraint from the dvdId column. (There may also be other UNIQUE constraints that need to be removed from the target table.)
If we only want to store one copy of the row from dvd, along with values from one matching row from each of the other tables, we could leave the UNIQUE constraint, and use an INSERT IGNORE statement to avoid throwing a "duplicate key error". Any rows where that error would have been thrown will be discarded, and won't be inserted into the target table.
Because the column references aren't qualified, we can't actually tell which table the dvdId column is beint returned from. We can't tell which table any of the columns are returned from. We can "guess" that genreId is being returned from the dvdGenre table, but for us to figure that out, we'd need to investigate the schema definition. It's not a problem for MySQL, it can lookup the table definitions a whole lot faster than we can.
We could aid to the future reader of that SQL statement by qualifying the column references with the tablename, or a table alias.

Related

How to sort a column based on another column to resolve can't add or update child row issue

I have a table which contains id and supervisorId. Id is the PK and supervisorId is the foreign key (Self Join).
When I try to insert the data into the table, mysql throws unable to add or update a child row error. Because of relationship between two columns, I can't populate the supervisorId column without Id column.
Is there any way to insert the data in a single query?
You need to insert the rows in two steps:
Insert the rows without supervisors (i.e. supervisor_id = NULL.
Then update the rows with the correct supervisor, when you know their ids.
It is not clear how you are processing the data. If you are trying to move rows from one table to another, you should probably ask another question, with sample data, desired results, and a clear explanation of what you want to accomplish.

Insert multiple records into a table based on AVG values from another table in mySQL

I have a mysql database with 2 tables. The first "spec" is a specification table, the second 'log' is table containing logged entries of previous measurements. Each part being logged is identified by a part number and test measurement. There may be many log entries for any given part number, but only 1 entry per part number in the 'spec' database giving the actual specification. What I need to do is obtain an average of the test measurement for every different part in the 'log' table, and insert this into the 'spec' table as a new specification. The log table will have already have been corrected to remove outliers.
I have been able to update existing records in the 'spec' table, but have been unable to insert records that do not already exist.
This works
update no_flow.spec s join
(select part, round(avg(cc),0) as avgcc
from no_flow.log l
group by part) l
on s.part = l.part and l.avgcc > 0
set s.cc = l.avgcc;
This does not work
INSERT INTO no_flow.spec set (part, cc) s join
SELECT part, avg(cc)
FROM no_flow.log l
WHERE id != 0
values (l.part, l.avgcc);
Suggestions?
If there is a unique index on part in spec you could use INSERT ... ON DUPLICATE KEY UPDATE Syntax
It would look something like this:
INSERT INTO noflow.spec (part, cc)
select
part as logPart,
round(avg(cc),0) as avgcc
from
no_flow.log
group
by logPart
ON DUPLICATE KEY UPDATE cc = VALUES(cc);
This inserts all the records from the inner SELECT into the spec table. When a given inserted record encounters a duplicate key error (i.e. there is already a record for the current part number) the ON DUPLICATE KEY clause updates the existing record by setting its cc column equal to the cc column on the record it was trying to insert.

How can i get all occurrences of a foreign key in a certain amount of tables?

I know, that there is a thing in MySQL called 'on delete cascade' and that means (as far as i can understand): when you delete a certain row in a table, all records in the other tables, that have a reference on it will be deleted too. And that happens without any other queries or delete statements.
So now my problem is: I have a situation, that is pretty similar to that one. There is a table (A) with a primary key column, and a certain amount of other tables (B, C, ...) have a column, which references (foreign key) to that column in table A. Now i have a row in A with the primary key 22 and i want to determine all the occurrences of 22 in the other tables.
So it is possible, that 22 occurs in C and F, but not in B, D or E ...
If it's possible to delete every reference with 'on delete cascade', can i realize my problem on a similar way?
My solution so far: i look up in every table, if there is a 22 in the foreign key column, but that may take a long time, when there is a large amount of tables/rows in it.
Are there any better solutions?

Add a Foreign Key to an Existing Table that Contains what would be Invalid FK Values (MYSQL)

I need to add a Foreign Key to a table that already exists and is populated with data that would contain invalid Foreign Key Values. (MYSQL)
I know there are several questions along these lines, but I can't seem to find any that answer my scenario.
Table and Data Structure
"GblTable" contains an "Org" field that needs to become a FK of the Org table. The Org table has a PK field called "number".
Currently, the GblTable contains non-existent Org numbers (ie. If the Org table has rows with PKs 1,2, and 3, GblTable might have rows with Org as 4 or 5). While this is the case, I cannot apply the constraint to reference GblTable.org to Org.number.
I believe the best approach for this particular situation will will be to set the FK field in those rows to NULL before I apply the constraint. NULL is a valid GblTable.Org value for the program, so this would achieve an acceptable outcome.
What I Have so Far
I want to set all GblTable.Org values to NULL where they do not match a valid Org.Number.
In pseudocode:
set GblTable.ORG to NULL
where the GblTable.number is one of the following:
( select all GblTable.numbers where the GblTable.Org does not match an existing Org.Number )
In Sql, but I get the error "You can't specify target table 'GblTable' for update in FROM clause":
update GblTable set Org=NULL
where number IN (
select number
from GblTable
where Org NOT IN (select number from Org)
)
What's the best way to achieve my requirement?
You don't need the extra level of subquery:
update GblTable set Org=NULL
where Org NOT IN (select number from Org)

Ensure combo of values are unique, but entered any number of times - Mysql

How can I enforce constraint checks to ensure that a given combination of values are unique, but can be entered any number of times?
Example: I have two columns: Group_ID and Group_Name. So all data with Group_ID = 1 will always have Group_Name as 'Test1'. What I want to prevent is someone entering 'Test2' into Group_Name where Group_ID=1. This should fail the insert. All this data is loaded directly into the DB without any UI, hence I cannot enforce these checks in application. So what I need is:
A unique constraint over multiple columns, but only for the given combination without checking how many times they have been entered.
Is there anything built in Mysql to do this?
You should normalize your table a little bit. The group_id,group_name pair should be in a separate table that defines your groups and then the table you're working with should only have group_id. Then you could add a foreign key from your table to the group table to ensure that your group_id values reference real groups.
If you can't normalize your tables then you'll probably have to use a before insert and before update trigger to ensure that Group_ID and Group_Name always come together as required.