Check if MySQL entry exists, if it does, overwrite other columns - php

I have a MySQL table set out as the following
UID | Thing1 | Thing2 | Date
The UID column has been set as unique and is made from the users ID + the date as an integer. I.E 7620150715
What I'd like to do is check to see if the UID exists, if it does, then update columns thing1 and thing2 with the latest information.
If the UID doesn't exist, then create a new row for all the information.
Currently, what works to enter is
$sql = "INSERT INTO things2 (uid, thing1, thing2, date) VALUES (:uid, :thing1,:thing2,:date)";
But this doesn't work after making UID unique.
I've found that the ON DUPLICATE KEY UPDATE statement seems to be what I'm looking for, but all answers appear to be adding +1 to the input, which is not what I want to do.
Some pseudo syntax for what I'm looking for would go like this
$sql = "INSERT INTO things2 (uid, thing1, thing2, date) VALUES (:uid, :thing1,:thing2,:date ON DUPLICATE KEY UPDATE (thing1, thing2) VALUES (:thing1, :thing2)";
What would be the correct syntax?

Your syntax is a little wrong. If the INSERT fails then you code an UPDATE with the standard UPDATE syntax like so.
$sql = "INSERT INTO things2
(uid, thing1, thing2, `date`)
VALUES (:uid, :thing1,:thing2,:date )
ON DUPLICATE KEY
UPDATE things2 SET thing1 = :thing1, thing2 = :thing2, `date` = :date";
Also date is a reserved word so its best to wrap it in backticks.

The easiest/most clear way needs two steps:
First do an INSERT OR IGNORE of just the (new) UID. Don't bother with the values yet, because you will update anyway. Just make sure that table allows this with proper defaults and not too many constraints:
INSERT OR IGNORE INTO things2 (uid) VALUES (:uid)
Then do an UPDATE ... SET a=b WHERE UID=.. to actually update the records:
UPDATE thing1=:thing1, thing2=:thing2 WHERE UID = :uid
(Not tested, and please check because I am more into C++/sqlite than in MySql/php)

Related

After inserting datetime created in PHP to MySQL table, no result is returned when same table is queried with same variable value

Problem Description
I have two tables in a MySql database which is intended to store form submission info. The first table contains contact info from the form, the second, user source info (i.e. IP address).
I am creating a datetime in PHP like so:
$timestamp = date('Y-m-d H:i:s');
Then, I am inserting into the first table (successfully) the contact form info, along with this datetime.
Now, what I want to do is get the primary key (auto-incrementing integer) from the first table which is associated with this datetime. So, I query the first table with this string: $db_query = "SELECT `unique_id` FROM `leads_contact_info` WHERE `timestamp` = '$timestamp'";
Herein lies my problem: when I query the table from PHP, it always returns '0'. But, if I go into the first table in PHPMyAdmin, copy and paste the datetime value from a given row into the query, then run the query from the PHPMyAdmin interface, it does indeed return the correct value.
Any help would be greatly appreciated as I'm getting to the, "I'm about to throw my computer out the window and me with it," stage of frustration.
Best
NOTE: In the below scripts, I have control structures for error handling/reporting, which I have omitted for the sake of clarity. Suffice it to say, they work and are not the source of the problem.
Original Script
// Create timestamp
$timestamp = date('Y-m-d H:i:s');
// Create query to insert contact info into first table
$db_query = "INSERT INTO `leads_contact_info` (`unique_id`, `timestamp`, `first_name`, `last_name`, `company_name`, `business_type`, `website`, `phone`, `phone_ext`, `email`, `time_of_week`, `time_of_day`, `notes`) VALUES (NULL, '$timestamp', '$first_name', '$last_name', '$company_name', '$business_type', '$website', '$phone', '$phone_ext', '$email', '$time_of_week', '$time_of_day', '$notes')";
// Execute query
$db_query_result = $db_connection->query($db_query);
// Create query to get primary key from last insertion
$db_query = "SELECT `unique_id` FROM `leads_contact_info` WHERE `timestamp` = '$timestamp'";
// Execute query
$db_query_result = $db_connection->query($db_query);
// Create query to insert source info into second table
$db_query = "INSERT INTO `leads_source_info` (`unique_id`, `from_page`, `referrer`, `user_agent`, `ip_address`) VALUES ('$unique_id', '$this_page', '$referrer', '$user_agent', '$ip_address')";
// Execute query
$db_query_result = $db_connection->query($db_query);
Edited Script (following suggestion from #SetSailMedia)
// Create timestamp
$timestamp = date('Y-m-d H:i:s');
// Create query to insert contact info into first table
$db_query = "INSERT INTO `leads_contact_info` (`unique_id`, `timestamp`, `first_name`, `last_name`, `company_name`, `business_type`, `website`, `phone`, `phone_ext`, `email`, `time_of_week`, `time_of_day`, `notes`) VALUES (NULL, '$timestamp', '$first_name', '$last_name', '$company_name', '$business_type', '$website', '$phone', '$phone_ext', '$email', '$time_of_week', '$time_of_day', '$notes')";
// Execute query
$db_query_result = $db_connection->query($db_query);
// Get primary key from last query
$unique_id = mysqli_insert_id();
// Create query to insert source info into second table
$db_query = "INSERT INTO `leads_source_info` (`unique_id`, `from_page`, `referrer`, `user_agent`, `ip_address`) VALUES ('$unique_id', '$this_page', '$referrer', '$user_agent', '$ip_address')";
// Execute query
$db_query_result = $db_connection->query($db_query);
Debugging Attempts
Unquoting '$timestamp' in both insertion and selection queries.
Various date format conversions on the PHP end of things (again, the insertion query is successful).
Added while loop with sleep(1) on selection query (while result from query == 0).
Tried using both $mysqli->insert_id and mysqli_insert_id($db_connection) to retrieve value of unique ID in first table. Both return 1 on first and follow up executions of the script (in other words, data is inserted into the second table with the unique ID of 1, which doesn't match the actual auto-incremented value of the most recent record in the first table).
Workaround (Not A Solution To The Original Problem)
After many attempts, I finally decided to opt for a workaround for this particular problem. That said, I'd like to leave the question open in case someone comes up with an answer or otherwise has the solution. Thanks to all who tried to help, especially #SetSailMedia.
As a workaround, I changed the DATETIME field in the first table to a TIMESTAMP, and set it to default to the current timestamp. Then, I increased the size of the primary key field to, and in PHP, created a custom integer unique ID via $unique_id = time() + rand(1, 999999999). I checked (via a while loop) to make sure that this unique ID did not already exist in the first table, then fired off the insertion query. Finally, I inserted into the second table with the same value as a unique ID.
Again, this is not a solution to the original problem, and I for one am curious to see what the issue is here, but I simply must move on with this project. I do hope someone else finds the information and efforts herein to be useful.
Why aren't you using mysql_insert_id() (or equivalent function in your database abstraction layer)? This returns the primary key after a successful insert.
Looking at your answers in the comments and the code you posted i see where is the problem:
-In the first table you insert the record with a null value in the unique_id field and then you tried to retrieve this unique id but you dont get a result.
-Then you posted this:
At this point, I'm ready to just pop an auto-incrementing unique ID on both tables, but I really would hate to do that. I feel like there is a solution to this problem.
There lies your problem, if you can pass a null in unique_id an the insert is a success but that field isn't autonumeric then that field is not_null and if thats the case it is also not the primary key.
Of course the SELECT fails because theres nothing to return and also the mysqli_insert_id because there are not autonumerics in the first table.
If you dont want or cant use a autonumeric then look at the uniqid function. The second table does not need any modification.

Multiple Insert in different tables with insert new AI

I have a PHP-script in which I can register news users.
Of course I want to insert things like username, password etc. (these values come from the user) but on the other side I want to insert his user_id (new user!) into another table.
My SQL
$sql = "
BEGIN;
INSERT INTO users (username, password, auth_lvl, realname, usercolor) VALUES ('$username', '$password', '$auth_lvl', '$realname', '$usercolor');
INSERT INTO users_startmodules (user_id, startmodule, enabled) VALUES ('(SELECT MAX(user_id)+1 FROM users)', 'newsmodule', '1');
COMMIT;
";
How can I solve this problem and is BEGIN; ... COMIT; the right choice when I want to get the query canceled if just one thing didn't work, because I don't want to have just a few entries in the worst case.
I suggest to change the type of user_id in users table to auto_increment with something like this:
alter table users alter column user_id INT NOT NULL AUTO_INCREMENT PRIMARY KEY
Now, Assuming that you have escaped the user input data:
$query="INSERT INTO users (username, password, auth_lvl, realname, usercolor) VALUES ('$username', '$password', '$auth_lvl', '$realname', '$usercolor');"
and run that:
$mysqli->query($query);
then get the userid with mysql_insert_id() function of MySQL or alternatively in PHP:
$userid=$mysqli->insert_id;
and:
$query="INSERT INTO users_startmodules (user_id, startmodule, enabled) VALUES ('$userid', 'newsmodule', '1');";
$mysqli->query($query);
This is too long for a comment.
To get the id that was just inserted, use last_insert_id(). This function is documented here.
Next, the answer to your question is to start a transaction. I would give you the syntax, but it is better for you to read the documentation on transactions before you start using them.
The key idea is that a transaction groups data modifications together. Either all take place or none do. Along the way, you can use commit or rollback, depending on whether or not you want to keep the changes or keep none of the changes.

IF EXISTS MySQL

I'm from a mssql background so it's difficult to get used to MySQL.
I have a table called users_settings. Within this table there are three columns; uid, name, value. Uid is a integer and refers to the user that owns that setting, the name is the name of the setting, the value, well, you guessed it, is the value.
What I'm trying to do is update these settings if it already exists, but if it doesn't, insert a new row.
My current query is as such (Note I'm using prepared statements):
IF EXISTS (SELECT * FROM users_settings WHERE name = ? AND uid = ?) THEN
UPDATE users_settings SET value = ? WHERE name = ? AND uid = ?;
ELSE
INSERT INTO users_settings (uid, name, value) VALUES (?, ?, ?);
END IF;
The issue I'm having is that when I attempt to prepare my statement, it returns false, which therefore suggests that the syntax is incorrect. After looking in to this, it looks like it's a SQL syntax error.
Would anybody be able to point me in the relative direction as to what may be occurring here, and where I may have got my syntax incorrect?
IN MySQL, if as a statement can only used in programming blocks -- stored procedures, functions, and triggers (this is not to be confused with if as a function, which can be used in almost any SQL statement).
You can do what you want in MySQL with a single statement, insert . . . on duplicate key update. For this to work, you need a unique index on name and uid:
create unique index users_settings_name_uid on users_settings(name, uid);
And then:
INSERT INTO users_settings (uid, name, value)
VALUES (?, ?, ?)
ON DUPLICATE KEY UPDATE value = VALUES(value);
There are two ways to fulfill your request in MySQL:
If you want to update an existing row or insert a new one if it does not exist then you should use INSERT ... ON DUPLICATE KEY UPDATE:
INSERT INTO users_settings (uid, `name`, `value`)
VALUES (?, ?, ?)
ON DUPLICATE KEY UPDATE `value` = VALUES(`value`);
This relies on an unique index that contains the columns uid and name. If it does not already exist, you can create it:
ALTER TABLE users_settings
ADD UNIQUE INDEX uid_name (uid, `name`);
You need it anyway because you want a single entry in the table for each user and setting name.
If you want to insert a row in the table and replace (discard) another one that already exists then you can use REPLACE:
REPLACE INTO users_settings (uid, `name`, `value`)
VALUES (?, ?, ?);
The syntax of REPLACE is similar with the one of INSERT (but it does not support ON DUPLICATE KEY UPDATE for obvious reasons). Internally it does a DELETE followed by an INSERT (it is just a shortcut). It discards the existing row (if any) and insert the new one. It also relies on the presence of the above mentioned index (that you have no matter how you update the values in the table).
For your situation both approaches have the same outcome because there is a single column (value) that is updated or replaced. In other situations only one of them is good.
Choose the one that you feel more appropriate for your workflow and your coding style.
INSERT INTO persona_opcion(nPerCodigo,nOpcCodigo,nPerOpcEstado)
SELECT '$codPer','$idOpc',1
FROM persona_opcion
WHERE NOT EXISTS(
SELECT nPerCodigo,nOpcCodigo,nPerOpcEstado
FROM persona_opcion
WHERE nOpcCodigo='$idOpc'
and nPerCodigo='$codPer'
)
LIMIT 1;
enter link description here

Updating a MySQL record with an auto-increment field as PK

I have a MySQL table with an auto-incrementing primary key (UID). The user can bring up a record in this table via a PHP form, where the UID is a $_GET variable. I would like the database to update the chosen record if it exists, but every time the user hits submit, a new record is created. This is what I've tried so far:
//Present the form
$form = $con->prepare("SELECT Name, Date, Time FROM forms WHERE UID = :uid");
$data = array('uid'=>$_GET['uid']);
$form->execute($data);
$row = $form->fetch(PDO::FETCH_ASSOC);
//Write new record to database. If the UID exists, update the record.
INSERT INTO forms (Name, Date, Time) VALUES (:name, :date, :time)
ON DUPLICATE KEY UPDATE Name=VALUES(Name),Date=VALUES(Date),Time=VALUES(Time);
This doesn't work. Do I need another unique key in the table, or am I missing something obvious?
INSERT INTO forms (`Name`, `Date`, `Time`) VALUES (:name, :date, :time)
ON DUPLICATE KEY UPDATE `Name`=:name, `Date`=:date, `Time`=:time;
This should be the query; I removed VALUES() from your code and added backticks and corrected your parameters.
And I recommend you to use backticks around column names so it doesn't get confused with other similar SQL keywords as example.

On duplicate Key update.. database key?

I have a table (id, name, price, menu_id)
I have a page in which every item's name and price is shown, and the users can edit it.
But when I submit, it creates new rows.
The index is on the primary key. Should it be on something else?
I tried the following:
INSERT INTO gerechten
SET gerecht_naam = :naam, gerecht_prijs = :prijs, menu_id = :menuid
ON DUPLICATE KEY
UPDATE gerecht_naam = :naam, gerecht_prijs = :prijs
your query will transform to an update whenever any unique key crashes in your table. Up to you to decide where this key should be placed on. For example, your query could be:
INSERT INTO `gerechten` (`name`, `price`, `menu_id`)
VALUES (:name, :price, :menuid)
ON DUPLICATE KEY UPDATE
name = :name,
price = :price
with a unique index on name AND menu_id for example. (I believe there can be several times the same name as long as it is in a different menu)
Of course if there are various fields combinations that must be unique this is a problematic situation and maybe you should use a different approach, such as a select ... lock statement to check previous existence of the values being edited.
You need to add a UNIQUE key to the gerech_naam column and/or to the gerech_prijs (you can have two columns define uniqueness of a row).
If you were to implement these unique keys to the table, you have to be aware that you would still have a problem because if you change the name or the price it could possibly insert in the DB because the data you provide doesn't exist in the table.

Categories