I have a MySQL Table that has a column that will AUTO_INCREMENT, another to store user-submitted data, and another column that defaults to CURRENT_TIMESTAMP.
My INSERT query is:
$query = $db->prepare("INSERT IGNORE INTO `UserData` (`user_data`) VALUES(?)");
$query->bind_param('s', $commentdata);
$query->execute();
However it is still inserting the duplicate values (if a user clicks submit multiple times). What is the best way to prevent this?
MySQL will not create duplicate auto increment ids (unless you have a very badly configured cluster) so presumably the duplicates you refer to are in a different attribute - you've only told us about user_data.
If you don't want duplicates in there then add a unique index on the column. You should also add error handling to deal with failures when the situation arises and remove the 'IGNORE'.
However you also need to think about your controlling logic (this hints that you probably have csrf vulnerabilities) and your user interface (why are you allowing users to submit the same form twice?)
I ended up using the following query:
INSERT INTO `UserData` (`post_num`, `user_data`)
SELECT ?, ? FROM `UserData`
WHERE NOT EXISTS (
SELECT * FROM `UserData` WHERE `post_num`= ? AND `user_data`=?
) LIMIT 1
Then I do $query->bind_param('isis', $post_number, $comment, $post_number, $comment); to bind the values.
This will check to make sure there are no duplicate comments on a post.
Note that my actual example inserts more information such as the user information and I check to make sure there are no duplicate comments from that certain user on a specific post.
The best way to prevent duplicate values in a MySQL table is for the table definition to use the UNIQUE or PRIMARY constraint. See the documentation for table creation syntax.
You may also want the value to be a KEY if you plan on performing lookups using that value.
Related
I have an SQL Database setup with rows of data already there. How do I update just one column of one row by grabbing the id (appointmentspage.php?id=1")?
I already have written the code to input the data into the correct position table I want, but I am having trouble selecting the id too
if(isset($_POST["submit"]))
try{
$sql = "INSERT INTO appointments (Notes)
VALUES ('".$_POST["Notes"]."')";
I feel like = $_GET['id']; or WHERE appointments.ApptID = :id should be used, but I can't fathom it.
Currently the 'Notes' column in my SQL table gets an input, but it creates a new empty row with only that data added. I want to select an existing row/entry and add the Notes to that.
On my site I have a set of examples for the basic use cases, you are welcome to check them out.
Your case would be UPDATE query using PDO.
First of all, "insert into an existing record" is called UPDATE. You need to check out your SQL textbook.
And yes, you need something like ApptID = :id in your query. However personally I prefer simple ? marks
So it should be something like
$sql = "UPDATE appointments SET notes=? WHERE ApptID=?";
$stmt= $dpo->prepare($sql);
$stmt->execute([$notes, $id]);
Note three shouldn't be any try or catch stuff around.
You need to define ApptID field as Primary Key with auto-increment field in database define. In MySQL, a primary key is a single field or combination of fields that uniquely defines a record. None of the fields that are part of the primary key can contain a NULL value. A table can have only one primary key.
Auto-increment allows a unique number to be generated automatically when a new record is inserted into a table. Often this is the primary key field that we would like to be created automatically every time a new record is inserted.
After that you can use that ApptID for update your existing data using Update query in MySQL
How can I insert more than one row for the same value
for example, each user has to submit 2 forms so the username is the same in each form but the information is different
I tried to use UPDATE but it removes the ole information and replaces it with the new one while I want to keep both
is there a way to do that?
insert into your_table (username, col2)
values ('user1', 1),
('user1', 2)
Have two tables, 'USERS' and 'FORMSUBMISSIONS'
When a user submits a form for the first time, a new entry is created in the USERS table, which is unique for each user, and would contain information connected to the user.
And whenever a form is submitted (including the first time), an entry is written to the FORMSUBMISSIONS table with the details of that submission, and a foreign key back to USERS.
That's a cleaner data model for this situation. It will also help future queries on the data. If you are limited to a single table for some reason, then successive inserts will work as above, as long as there is no unique key on the USER field.
you can add duplicate data just your primary key can't be duplicated because it causes primary key constraint. so what you can do is have an extra column let's say "ID" make it your primary key. While submitting the row keep on adding ID column's value by one, rest of the data could be same.
It depends on whether your USERNAME column allows duplicates.
If it's the primary key of the table, your table schema doesn't support what you want to do, because PK should be UNIQUE.
If your USERNAME column allows duplicates, you can use INSERT:
declare #username varchar(max) = 'your_username' --declare a variable to use the same username
insert into table_name (username, form_data)
values(#username, 'form_data_1')
,(#username, 'form_data_2')
It also depends on how you're executing the SQL statement. I would definately go and create stored procedure to do this insert.
you can use bulk insert query for that. as suggested by #huergen but make sure that your username or any field that might be in form data does not have UNIQUE key index. you can also add another field that works like PRIMARY key in that table.so many ways to do but it depends upon your requirement.
Use below insert format to get your desired result:
insert into Table_name(Field1, Field2)
SELECT 'user_1', 1 UNION ALL
SELECT 'user_1', 2
I have a MySQL query that looks like this:
INSERT INTO beer(name, type, alcohol_by_volume, description, image_url) VALUES('{$name}', {$type}, '{$alcohol_by_volume}', '{$description}', '{$image_url}')
The only problem is that name is a unique value, which means if I ever run into duplicates, I get an error like this:
Error storing beer data: Duplicate entry 'Hocus Pocus' for key 2
Is there a way to ensure that the SQL query does not attempt to add a unique value that already exists without running a SELECT query for the entire database?
You could of course use INSERT IGNORE INTO, like this:
INSERT IGNORE INTO beer(name, type, alcohol_by_volume, description, image_url) VALUES('{$name}', {$type}, '{$alcohol_by_volume}', '{$description}', '{$image_url}')
You could use ON DUPLICATE KEY as well, but if you just don't want to add a row INSERT IGNORE INTO is a better choice. ON DUPLICATE KEY is better suited if you want to do something more specific when there are a duplicate.
If you decide to use ON DUPLICATE KEY - avoid using this clause on tables with multiple unique indexes. If you have a table with multiple unique indexes ON DUPLICATE KEY-clause could be giving unexpected results (You really don't have 100% control what's going to happen)
Example: - this row below only updates ONE row (if type is 1 and alcohol_by_volume 1 (and both columns are unique indexes))
ON DUPLICATE KEY UPDATE beer SET type=3 WHERE type=1 or alcohol_by_volume=1
To sum it up:
ON DUPLICATE KEY just does the work without warnings or errors when there are duplicates.
INSERT IGNORE INTO throws a warning when there are duplicates, but besides from that just ignore to insert the duplicate into the database.
As it just so happens, there is a way in MySQL by using ON DUPLICATE KEY UPDATE. This is available since MySQL 4.1
INSERT INTO beer(name, type, alcohol_by_volume, description, image_url)
VALUES('{$name}', {$type}, '{$alcohol_by_volume}', '{$description}',
'{$image_url}')
ON DUPLICATE KEY UPDATE type=type;
You could also use INSERT IGNORE INTO... as an alternative, but the statement would still throw a warning (albeit, instead of an error).
Yes, there is. You can use the ON DUPLICATE KEY clause of mysql INSERT statement. The syntax is explained here
INSERT INTO beer(name, type, alcohol_by_volume, ...)
VALUES('{$name}', {$type}, '{$alcohol_by_volume}', ...)
ON DUPLICATE KEY UPDATE
type={$type}, alcohol_by_volume = '{$alcohol_by_volume}', ... ;
Yes, by first selecting the name from the database, and if the result of the query is not null (zero records), then the name already exists, and you have to get another name.
Quite simply - your code needs to figure out what it wants to do if something's trying to insert a duplicate name. As such, what you need to do first is run a select statement:
SELECT * FROM beer WHERE name='{$name}'
And then run an 'if' statement off of that to determine if you got a result.
if results = 0, then go ahead and run your insert.
Else ... whatever you want to do. Throw an error back to the user? Modify the database in a different way? Completely ignore it? How is this insert statement coming about? A mass update from a file? User input from a web page?
The way you're reaching this insert statement, and how it should affect your work flow, should determine exactly how you're handling that 'else'. But you should definitely handle it.
But just make sure that the select and insert statements are in a transaction together so that other folks coming in to do the same sort of stuff isn't an issue.
I have a form and a database table named reports. I have a date field (primary key) and a textarea named changes to say what's been changed on that date. If the date is the same I want to be able to overwrite the information in the 'changes' column for that date.
My insert command, which works on its own, is as follows:
mysql_query("
INSERT INTO reports (thedate,changes)
VALUES ('$_POST[thedate]','$_POST[changes]')
");
I understand that I'll need to use ON DUPLICATE KEY UPDATE after my INSERT but after numerous attempts I cannot get it right. Not only do things no update but it seems to break my insert command so even a new row isn't added to the database.
Apologies if this is a duplicate question. After lots of searching and lots of trying I cannot get it to work.
Have a look att REPLACE.
REPLACE works exactly like INSERT, except that if an old row in the
table has the same value as a new row for a PRIMARY KEY or a UNIQUE
index, the old row is deleted before the new row is inserted.
Note that if you have a foreign key with an action ON DELETE it will be triggered when using REPLACE since it does a delete followed by an insert .
Using ON DUPLICATE KEY it could look like this:
INSERT reports (thedate, changes) VALUES ('$_POST[thedate]', '$_POST[changes]')
ON DUPLICATE KEY UPDATE changes = '$_POST[changes]'
This is the plain SQL query:
INSERT INTO reports (thedate, changes)
VALUES ('2011-11-10', 'Lorem ipsum')
ON DUPLICATE KEY UPDATE changes=VALUES(changes)
http://dev.mysql.com/doc/refman/5.5/en/insert-on-duplicate.html
Now, you absolutely need to sit down and try to understand what SQL is and how it interacts with PHP and differs from it. You are using PHP to compose strings that happen to be code from another language called SQL. The way you are doing it, the resulting code can be valid SQL or not, and it'll depend of the arbitrary data sent by any anonymous visitor. In the best case, your script will crash. In the worse case, the visitor will be able to read confidential data or alter your database. Here's the example in the manual page for mysql_query():
// This could be supplied by a user, for example
$firstname = 'fred';
$lastname = 'fox';
// Formulate Query
// This is the best way to perform an SQL query
// For more examples, see mysql_real_escape_string()
$query = sprintf("SELECT firstname, lastname, address, age FROM friends
WHERE firstname='%s' AND lastname='%s'",
mysql_real_escape_string($firstname),
mysql_real_escape_string($lastname));
// Perform Query
$result = mysql_query($query);
This should work:
mysql_query("INSERT INTO reports (thedate,changes) VALUES ('$_POST[thedate]','$_POST[changes]') ON DUPLICATE KEY UPDATE changes=VALUES(changes)");
Disadvantage of using REPLACE is that it's not standard SQL but a MySQL extension. Beside that, when using auto incremented columns, REPLACE will reinsert with a different value. I won't recommend it to anyone.
Edit: ON DUPLICATE KEY isn't standard SQL either. Sorry!
I have a table of projects belonging to various users:
project_id, owner_user_id, project_name
I do not need the project_names to be globally unique to the table, so making project_name UNIQUE does not help. I would just like to prevent the user from creating duplicate project_names on INSERT or UPDATE.
Upon INSERT/UPDATE, I simply want to check if there is already a project_name belonging to a specific owner_user_id, and if it already exists, the INSERT/UPDATE should fail.
I could use a SELECT to first check for existence of the project_name within the user's projects, and then only do an INSERT/UPDATE if the select returns no results. But this is multi-threaded and another thread could INSERT the same project_name immediately after I perform the SELECT but before the INSERT/UPDATE. Putting this all into a transaction feels like overkill. Is there a single query that can perform this instead?
You could add a UNIQUE constraint on the two columns as a pair:
alter table your_table add unique (owner_user_id, project_name)
That will ensure that project_name values are unique per-user. You'll want to have a look at your collation set up to make sure your project_name values are compared without regard to case. Or you could standardize the project names to title case before hitting the database.
Don't try to maintain data integrity by hand unless you have to, let the database take care of your constraints whenever possible.
This does need to be in a transaction. You need to retrieve some information ("which names are already in use?") and then act on it ("if my name is not in use, then use it"). This must be done atomically.
As you have correctly surmised, there is a race condition if the insert does not happen atomically after the check.
This is what transactions are for.
You can add a unique constraint on both fields
CONSTRAINT C_UNICITY UNIQUE (owner_user_id, project_name)
Each time you try to insert or update a record which present duplicate, you'll get a sql error
$result = mysql_query("select * from Project where owner_user_id='1';");
if (mysql_affected_rows()==0) {
$result = mysql_query("insert into Project (projectname) values ('pojectname');");
Depending on database referential integrity violations to throw errors for you to trap is not generally a preferred form of UI validation - you generally want something at a higher abstraction level anyway. But there's nothing particularly "overkill" about using transactions and UNIQUE constraints liberally to protect your data as much as your users.