phpMyAdmin - Database values changing - mysql

I created a table with two columns in phpMyAdmin and I set the first column as a primary key.
Let's say that we have stored some data in the table. For example:
Column A Column B
x1 y1
x2 y2
x3 y3
If I try to send some data like (x1, y4), will y1 be set to y4?
If not is there a setting to do it from phpMyAdmin?
Or Do I need to use UPDATE?

You should use UPDATE or INSERT ON ON DUPLICATE KEY UPDATE
MORE INFO # http://dev.mysql.com/doc/refman/5.0/en/insert-on-duplicate.html

trying to insert a row with an existing primary key will cause an error, and that's exactly why no one uses things that might be duplicated as primary keys, to change the value of the existing row, you must use UPDATE, there is no other solution, but if you want to insert a new row, my advice is to go main stream, either use an autoincremented id as primary key, or use things like GUID(windows only).

Related

INSERT or UPDATE if condition over two columns (regardless of order) is met

I want to do the following:
INSERT INTO table1 (term1, term2, number) values ('A','B',10);
however if values A and B are already present in table1 regardless of their order, ie. the predicate
(term1='A' && term2='B') OR (`term1='B' && term2='A')
holds true, then I just want to update column number. Is there any way of doing that?
A (perhaps the) clean way to handle this situation is to use INSERT ... ON DUPLICATE KEY UPDATE, read the documentation.
If you specify ON DUPLICATE KEY UPDATE, and a row is inserted that
would cause a duplicate value in a UNIQUE index or PRIMARY KEY, MySQL
performs an UPDATE of the old row
The important part is would cause a duplicate value in a UNIQUE index. Therefore you need to create an multicolumn unique index.
Now I'm not sure if you can manage the order that way, therefore I'd create an extra field with the concatenation of the sorted values of your fields, and have that field uniquely indexed.
EDIT: Instead of storing the concatenation your fields, you could also just store the hash and index it.
Thanks #okiharaherbst,
This is what I did: I added new column "uniqueKey" as primary key and insert goes as follows:
INSERT INTO table1(term1,term2,num,uniquekey) VALUES ( "a","b",10,
concat(greatest(term1,term2),least(term1,term2))) on duplicate key update num=10;

Does mySql have an update/insert combo which inserts if the update fails?

I'm not optimistic that this can be done without a stored procedure, but I'm curious if the following is possible.
I want to write a single query insert/update that updates a row if it finds a match and if not inserts into the table with the values it would have been updating.
So... something like
updateInsert into table_a set n = 'foo' where p='bar';
in the event that there is no row where p='bar' it would automatically insert into table_a set n = 'foo';
EDIT:
Based on a couple of comments I see that I need to clarify that n is not a PRIMARY KEY and the table actually needs the freedom to have duplicate rows. I just have a situation where a specific entry needs to be unique... perhaps I'm just mixing metaphors in a bad way and should pull this out into a separate table where this key is unique.
I would enforce this with the table schema - utilize a unique multi-column key on the target table and use INSERT IGNORE INTO - it should throw an error on a duplicate key, but the insert will ignore on error.

Importing MySQL records with duplicate keys

I have two MySQL databases with identical table structure, each populated with several thousand records. I need to merge the two into a single database but I can't import one into the other because of duplicate IDs. It's a relational database with many linked tables (fields point to other table record IDs).
Edit: The goal is to have data from both databases in one final database, without overwriting data, and updating foreign keys to match with new record IDs.
I'm not sure how to go about merging the two databases. I could write a script I suppose, but there's many tables and it would take a while to do. I wondered if anyone else had encountered this problem, and the best way to go about it?
Just ignore the duplicates. The first time the key is inserted, it'll be inserted. The second time it will be ignored.
INSERT IGNORE INTO myTable (SELECT * FROM myOtherTable );
See the full INSERT syntax here.
The trick was to increment the IDs in one database by 1000 (or something won't overlap data in the target database), then import it.
Thanks for everyone's answers.
Are the duplicate IDs supposed to correspond to each other? You could create a new table with an auto increment field and save the existing keys as two columns.
That would just be a 'bulk copy' though. If there is some underlying relationship then that would dictate how to combine the data.
If you have two tables A1 and A2 and you want to merge this to AA you can do this:
INSERT INTO aa SELECT * FROM A1;
INSERT INTO aa SELECT * FROM A2 ON DUPLICATE KEY
UPDATE aa.nonkeyfield1 = a1.nonkeyfield1,
aa.nonkeyfield2 = a1.nonkeyfield2, ....;
This will overwrite fields with duplicate keys with A2 data.
A slightly slower method with simpler syntax is:
INSERT INTO aa SELECT * FROM A1;
REPLACE INTO aa SELECT * FROM A2;
This will do the same thing, but will not update duplicate rows, but instead delete the row from A1 first and then reinsert the data from A2.
If you want to merge a whole database with foreign keys, this will not work, because it will break the links between tables.
If you have a whole database and you do not want to overwrite data
I'd import the first database as normal into database A.
import the second database into a database B.
Set all foreign keys as on update cascade.
Double check this.
Now run the following statement on all tables on database B.
SELECT #increment:= MAX(pk) FROM A.table1;
UPDATE B.table1 SET pk = pk + #increment WHERE pk IS NOT NULL
ORDER BY pk DESC;
(The where clause is to stop MySQL from giving an error in strict mode)
If you write a script with those two lines per table in your database you can then insert all tables into database AA, remember to disable foreign key checks during the update with
SET foreign_key_checks = 0;
... do lots of inserts ...
SET foreign_key_checks = 1;
Good luck.
Create a new database table with an autoincrimented primary key as the first column. Then add the column names from your databases and import each one. Then just drop the old primary field, and rename the new one to match your primary name.

Fastest way to modify a decimal-keyed table in MySQL?

I am dealing with a MySQL table here that is keyed in a somewhat unfortunate way. Instead of using an auto increment table as a key, it uses a column of decimals to preserve order (presumably so its not too difficult to insert new rows while preserving a primary key and order).
Before I go through and redo this table to something more sane, I need to figure out how to rekey it without breaking everything.
What I would like to do is something that takes a list of doubles (the current keys) and outputs a list of integers (which can be cast down to doubles for rekeying).
For example, input {1.00, 2.00, 2.50, 2.60, 3.00} would give output {1, 2, 3, 4, 5).
Since this is a database, I also need to be able to update the rows nicely:
UPDATE table SET `key`='3.00' WHERE `key`='2.50';
Can anyone think of a speedy algorithm to do this? My current thought is to read all of the doubles into a vector, take the size of the vector, and output a new vector with values from 1 => doubleVector.size. This seems pretty slow, since you wouldn't want to read every value into the vector if, for instance, only the last n/100 elements needed to be modified.
I think there is probably something I can do in place, since only values after the first non-integer double need to be modified, but I can't for the life of me figure anything out that would let me update in place as well. For instance, setting 2.60 to 3.00 the first time you see 2.50 in the original key list would result in an error, since the key value 3.00 is already used for the table.
Edit: I guess what this really abstracts to is this:
I need a way to convert an ordered map keyed with doubles into an ordered map keyed with integers, where at no point does there ever exist two values for one key (which is a violation of a map anyway).
I'm assuming you'll be able to take the database down at some point to make this conversion.
Note: I am NOT a MySQL user. My DB of choice is PostgreSQL, so there MAY BE SYNTAX ERRORS here between how MySQL does it and Pg does it. But this should give you a good idea.
First, make a keymap table that maps old keys to new:
create table keymap (
oldkey decimal,
newkey integer autoincrement
)
Make sure you index keymap because we're going to be lookups aplenty on it.
create unique index keymap_oldkey on keymap(oldkey);
Then fill it with old keys and let MySQL create the new ones:
insert into keymap
select distinct `key` from fribbles order by `key`
Now you'll have keymap with all the old keys, and because you haven't specified a new key, you'll have the autoincrement on the newkey column will populate, and your table will look like.
oldkey newkey
----------------
1.5 1
1.6 2
1.93 3
3.1 4
Now, add a newkey column to your tables that need it
alter table fribbles add column newkey integer
Don't make it autoincrement, because otherwise it will get populated at alter time, and we don't need that.
Now, finally, update the fribbles table:
update fribbles f
set newkey = ( select newkey from keymap m where m.oldkey = f.`key` )
Finally, now that you have newkey populated, you can drop the old one.
alter table fribbles drop column `key`;
alter table fribbles alter column newkey rename to `key`;
I hope that gives you a decent plan of attack.
I would just add an int column (that allows NULL values) to the table, then do a cursor- or code-based run where I sort by the original whacked-out double PK column and then iterate through the records writing an incremented value into the new int column. Then update the table by changing the PK to the new int column and deleting the old PK.
"Here", as they say in France.

Is there "UPDATE value IF NO SUCH ROW INSERT yyy" in MySQL?

I want to update a table value on Mysql 5 but if the key does not exist create it.
The way I found to do it is by:
INSERT yyy ON DUPLICATE KEY UPDATE field;
The question is : is the format above less efficient than other ways to do it (As the insert will happen only once and update will happen very often)?
for example:
$result = UPDATE field;
if (num_rows_effected($result)==0) INSERT yyy
Furthermore: Is there a better way to do this in Mysql: for example a kind of:
UPDATE value IF NO SUCH ROW INSERT yyy;
Update: For those who suggested REPLACE, here is an extension to my question:
"Thanks! I need to increase a counter that is already in the table (if it exists). If not create a table row with value 1 for this column. How can I do update with this format (REPLACE)? "
There is a REPLACE also.
INSERT ON DUPLICATE KEY UPDATE will fire UPDATE triggers when it will stumble upon a duplicate key and won't violate FK's in case on UPDATE.
REPLACE will fire DELETE and INSERT triggers, and will violate FK's referencing the row being REPLACE'd.
If you don't have any triggers or FK's, then use INSERT ON DUPLICATE KEY UPDATE, it's most efficient.
You seem to be looking for this query:
INSERT
INTO table (key, counter)
VALUES (#key, 1)
ON DUPLICATE KEY UPDATE
counter = counter + 1
You cannot do this with REPLACE unless you have selected previous value of the counter before running the query.
P. S. REPLACE appeared in MySQL before ON DUPLICATE KEY UPDATE and is being kept only for compatibility. There is no performance increase from using it.
Yes, you can use the 'replace' syntax:
REPLACE INTO table1 (key, col1, col2) values (1, 'val1','val2');
This is a feature specific to MySQL and is not necessarily implemented in other databases.
As for efficiency, my guess is that a straight update will be faster, since MySQL essentially catches the duplicate key error and handles it accordingly. However, unless you are doing large amounts of insert/updates, the performance impact will be fairly small.
Look at the REPLACE command, it meets your requirements.