MySql Update if exists insert if not - php

I'm trying to insert new to the table or to update the previous one in the same query.I can solve it with a bit of php code but my goal is to make it all in sql.
The problem
My app has names in different languages, I can add new languages to it.When i add new languages the translations for my products raise.
My goal is to send the script information ,and if two columns are same than the data should be updated, but if they are not they should be updated.
Here is some of my query:
"INSERT INTO product_name(link,product_id,language)
VALUES(:link,:product_id,:language) ON DUPLICATE KEY UPDATE
link=:link,product_id=:product_id,language=:language"
This query above solves one portion of the problem, but when i want to change the link it adds new data.My goal is to change the link ,and if the product_id and language are same in that row than it should be updated,if not than a new one shall be added.Unique wont solve the problem since i need to use same languages and id's in the table.

I think you just need a unique constraint on (product_id, language) -- and no unique constraint or primary key on all three columns.
CREATE UNIQUE INDEX unq_productname_product_language ON product_name(product_id, language);
This requires that the pair of values be unique, not each one individually.
Then this should do what you want:
INSERT INTO product_name(link, product_id, language)
VALUES (:link, :product_id, :language)
ON DUPLICATE KEY UPDATE link = VALUES(link);
Notice that this version uses VALUES(link). This uses the value being inserted in the statement. I think that is clearer than repeating the expression.

Related

Inserting mysql foreign keys and primary keys in a transaction.

Just looking for some tips and pointers for a small project I am doing. I have some ideas but I am not sure if they are the best practice. I am using mysql and php.
I have a table called nomsing in the database.
It has a primary key called row id which is an integer.
Then I have about 8 other tables referencing this table.
That are called nomplu, accsing,accplu, datsing, datplu for instance.
Each has a column that references the primary key of nomsing.
Withing my php code I have all the information to insert into the tables except one thing , the row id primary key of the nomsing table. So that php generates a series of inserts like the following.
INSERT INTO nomsing(word,postress,gender) VALUES (''велосипед","8","mask").
INSERT INTO nomplu(word,postress,NOMSING?REFERENCE) VALUES (''велосипеды","2",#the reference to the id of the first insert#).
There are more inserts but this one gets the point across. The second insert should reference the auto generated id for the first insert. I was this to work as a transaction so all inserts should complete or none.
One idea I have is to not auto generate the id and generate it myself in php. That way would know the id given before the transaction but then I would have to check if the id was already in the db.
Another idea I have is to do the first insert and then query for the row id of that insert in php and then make the second insert. I mean both should work but they don't seem like an optimal solution. I am not too familiar with the database transactional features but what would be the best approach to do in this case. I don't like the idea of inserting then querying for the id and then running the rest of the queries. Just seems very inefficient or perhaps I am wrong.
Just insert a row in the master table. Then you can fetch the insert id ( lastInserId when on PDO) and use that to populate your other queries.
You could use the php version as given by JvdBerg , or Mysql's LAST_INSERT_ID. I usually use the former option.
See a similar SO question here.
You could add a new column to the nomsing table, called 'insert_order' (or similar) with a default value of 0, then instead of generating one SQL statement per insert create a bulk insert statement e.g.
INSERT INTO nomsing(word,postress,gender, insert_order)
VALUES (''велосипед","8","mask",1), (''abcd'',"9","hat",2).....
you generate the insert_order number with a counter in your loop starting at one. Then you can perform one SELECT on the table to get the ids e.g.
SELECT row_id
FROM nomsing
WHERE insert_order > 0;
now you have all the IDs you can now do a bulk insert for your following queries. At the end of your script just do an update to reset the insert_order column back to 0
UPDATE nomsing SET insert_order = 0 WHERE insert_order > 0;
It may seem messy to add an extra column to do this but it will add a significant speed increase over performing one query at a time.

Auto-incrementing field that isn't a primary key

In my MySQl table I have two fields, id and order. id is an auto-incrementing primary key and I want order's initial value to match this, but to also be editable, not a key and with no uniqueness constraints. How can my database insert method achieve this? Is it possible to do so without requerying to find the last inserted id?
I'm using paris/idiorm so a solution making use of their features would be handy, although plain SQL and php is fine too.
In MySQL (since version 5.0.2) you can create trigger.
Try this on non-production database:
create trigger default_order_value AFTER INSERT ON orders
UPDATE order SET order = id WHERE id = new.id;
It may not work in that way as you wish, but you can edit it. This is another trigger example:
CREATE TRIGGER default_order
BEFORE UPDATE ON orders
REFERENCING NEW ROW AS n
n.order = n.id;

Merge several mySQL databases with equivalent structure

I would like write a php script that merges several databases, and I would like to be sure of how to go around it before I start anything.
I have 4 databases which have the same structure and almost same data. I want to merge them without any duplicate entry while preserving (or re-linking) the foreign keys.
For example there is a db1.product table which is almost the same as db2.products so I think I would have to use LIKE comparison on name and description columns to be sure that I only insert new rows. But then, when merging the orders table I have to make sure that the productID still indicates the right product.
So I thought of 2 solutions :
Either I use for each table insert into db1.x as select * from db2.x and then make new links and check for duplicate using triggers.
Either I delete duplicate entries and update new foreign keys (after having dropped constraints) and then insert row into the main database.
Just heard of MySQL Data Compare and Toad for mySQL, could they help me to merge tables ?
Could someone indicate to me what should be the right solution ?
sorry for my english and thank you !
First thing is how are you determining whether products are the same? You mentioned LIKE comparison on name and description. You need to establish a rule what says that product is one and the same in your db1, db2 and so on.
However, let's assume that product's name and description are the attributes that define it.
ALTER TABLE products ADD UNIQUE('name', 'description');
Run this on all of your databases.
After you've done that, select one of the databases you wish to import into and run the following query:
INSERT IGNORE INTO db1.products SELECT * FROM db2.products;
Repeat for the remaining databases.
Naturally, this all fails if you can't determine how you're going to compare the products.
Note: never use reserved words for your column names such as word "name".
Firstly, good luck with this - sounds like a tricky job.
Secondly, I wouldn't do this with PHP - I'd write SQL to do the work, assuming this is a one-off migration task and not a recurring task.
As an approach, I would do the following.
Create a database with the schema you want - it sounds like each of your 4 databases have small variations in the schema. Just create the schema for now, don't worry about the data.
Create a "working" database, with the same schema, but with columns for "old" primary keys. For instance:
table ORDER
order_id int primary key auto increment
old_order_id int not null
...other columns...
table ORDER_LINE
order_line_id int primary key auto increment
old_order_line_id int not null
order_id int foreign key
...other columns...
Table by table, Insert into your working database from your first source database. Let the primary keys auto_increment, but put the original primary key into the "old_" column.
For instance:
insert into workingdb.orders
select null, order_id, ....other columns...
from db1.orders
Where you have a foreign key, populate it by finding the record in the old_ column.
For instance:
insert into workingdb.order_line
select null, ol.order_line_id, o.order_id
from db1.order_line ol,
workingdb.order
where ol.order_id = o.old_order_id
Rinse and repeat for the other databases.
Finally, copy the data from your working database into the "proper" database. This is optional - it may help to retain the old IDs for lookups etc.

How to check insert values are different given same primary key?

If I have an insert statement with a bunch of values where the first value is an id that's also the primary key to my database, how can I check if everything else in those values is not completely the same and to update the fields that are different? (second part not necessary for an answer, but it'd be nice. If it's too convoluted to do the second part I can just delete the record first and then insert the full line of updated values)
I'm guessing that it has something to do with SELECT FROM TABLE1 * WHERE id=1 and then somehow do an inequality statement with the INSERT INTO TABLE1 VALUES ('1','A'... etc.) but I'm not sure how to write that.
Edit: I think I asked the question wrong so I'll try again:
I have a database that has first column id that is a primary key and then a lot of other columns, too long to type out by hand. I have a script that will get data and I will not know if this data is a duplicate or not e.g.
id value
1 dog
2 cat
if the new info coming in is "1, dog" then I need a signal (say boolean) that tells me true, if the new info is "1, monkey" then I need a signal that tells me false on the match and then update every single field. The question is how do I generate the boolean value that tells me whether the new values with the same id is completely identical to the one in the db? (It has to check every single filed of long list of fields that will take forever to type out, any type of output would be good as long as I can tell one means it's different and one means it's the same)
A side question is how do I update the row after that since I don't want to type out every single field, my temporary solution is to delete the row with the out of date primary id and then insert the new data in but if there is a fast way to update all columns in a row that'd be great.
MySQL can do "on duplicate key update" as part of the insert statement:
INSERT INTO table (id, ...) VALUES ($id, ...)
ON DUPLICATE KEY UPDATE somefield=VALUES(somefield), ...=VALUES(...)
Simple and effective. You only specify the fields you want changed if there is a primary key duplication, and any other fields in the previously-existing record are left alone.

Alter MySQL column with values to auto increment

I had a hard time with the title, so let me explain.
What I'm doing is using the jQuery UI to create sortable list elements on a page. Once the order is submitted, php assigns an incrementing value to the list elements based on their order, drops the existing id column, creates a new id column and inserts each list elements value WHERE title=x. This creates the proper order of ID's, and is working fine.
What I'd like to do now is change the column to auto_increment, such that if I insert a new entry, the id is assigned automatically, one number higher than the greatest number generated by the php script. I'm not using any foreign keys or anything, just this simple table.
Is this possible?
My mistake, I misread your question. You do not want to use the database itself to provide numbering based on your sort order. You can however use the SQL query itself to return an incrementing field. One sec and I'll update with that info...
Ok, here it is:
you need to use a variable like
set #n=0;SELECT
#n:=#n+1 as 'n',
col1,
col2
from table
However, i highly recommend you just create the numbering in your php code if at all possible.
----------------Original Post----------------
This is pretty easy with phpmyadmin. Let me know if your unable to install that and I'll dig up the necessary SQL.
All heck, here is the SQL:
alter table t1 modify f1 int(4) auto_increment
alter TABLE tbl auto_increment = xxx; //change xxx to be the next id it should use
you may need to run these in opposite order depending on your existing data set it will fail to add auto_increment if you don't change the value of auto_increment to be something not already in use.

Categories