I am currently starting web development and am now working on a very simple script that posts entry data from a from to a mysql database. But the problem I have been encountering is that when I submit the form I get the following error:
Error: Duplicate entry '0' for key 'PRIMARY'
To me it seems a really weird error as the table is completely empty, ID is set to auto_increment and I am not trying to assign any value to it.
I am using Xampp for my localhost on Mac OS btw.
This is my form (.php):
This is my mysql entry script (.php):
The result is this:
This is the database setup:
The weird thing is that when the table is empty, and I insert through the form the first time, something does end up in the database. But it is missing "email" and "password" and shows "NULL". The second time I use the form, nothing is added in the database:
Your id column does not seem to be auto-incrementing. It is not generating a new id for every row. It just defaults to 0 if you don't supply a value for it.
Nonetheless there's a UNIQUE/PRIMARY constraint on that column, so the id 0 cannot occur more than once. Since you're not supplying an id and MySQL isn't generating one (because the column isn't auto-incrementing), you cannot insert more than one row.
You're issuing three separate INSERT INTO statements which will result in three separate rows to be inserted (if you could insert more than one row, see above), each with a different value set; but never one row with all values set.
So:
Make your id column actually auto-incrementing.
Prepare a single INSERT INTO statement which inserts all values in one go:
INSERT INTO members (name, email, password) VALUES (.., .., ..)
See Why shouldn't I use mysql_* functions in PHP? and stop using mysql_*. Learn about prepared statements, read The Great Escapism (Or: What You Need To Know To Work With Text Within Text) for why.
Related
I have a table that looks like (irrelevant columns subtracted):
PRIMARY KEY(AUTO-INCREMENT,INT),
CLIENTID(INT),
CLIENTENTRYID(INT),
COUNT1(INT),
COUNT2(INT)
Now, the CLIENTID and CLIENTENTRYID is a unique combined index serving as a duplication prevention.
I use PHP post input to the server. My query looks like:
$stmt = $sql->prepare('INSERT INTO table (COUNT1,COUNT2,CLIENTID,CLIENTENTRYID) VALUES (?,?,?,?) ON DUPLICATE KEY UPDATE COUNT1=VALUES(COUNT1),COUNT2=VALUES(COUNT2)');
$stmt->bind_param("iiii",$value,$value,$clientid,$cliententryid);
The SQL object has auto commit enabled. The "value" variable is reused as the value in COUNT1 and COUNT2 should ALWAYS be the same.
Okay - that works fine, most of the time, but randomly, and I cannot figure out why, it will post 0 in COUNT2 - for an entirely different row.
Any ideas how that might occur? I can't see a pattern (it doesn't happen after a failed attempt, which is why the unique index exists, so that a new attempt will not cause duplicates). It seems to be completely random.
Is there something I've misunderstood about ON DUPLICATE KEY UPDATE? The VERY weird thing is that it updates A DIFFERENT row incorrectly - not the one you insert.
I realize other factors might affect this, but now I'm trying to rule out my SQL logic as a source of error.
Aside from the PRIMARY KEY on the auto_increment column, there is only ONE UNIQUE key defined the table, and that's defined on (CLIENTID,CLIENTENTRYID), right?
And there are no triggers defined on the table, right?
And you are (obviously) using a prepared statement with bind placeholders.
It doesn't really matter if those two columns (CLIENTID and CLIENTENTRYID) are defined as NOT NULL or not; MySQL will allow multiple rows with NULL values; that doesn't violated the "uniqueness" enforced by a UNIQUE constraint. (This the same as how Oracle treats "uniqueness" of NULL values, but it is different from how SQL Server enforces it.)
I just don't see any way that the statement you show, that is:
INSERT INTO `mytable` (COUNT1,COUNT2,CLIENTID,CLIENTENTRYID) VALUES (?,?,?,?)
ON DUPLICATE KEY
UPDATE COUNT1 = VALUES(COUNT1)
, COUNT2 = VALUES(COUNT2)
... theres no way that Would cause some other row in the table to be updated.
Either the insert action succeeds, or it throws a "duplicate key" exception. If the "duplicate key" exception is thrown, the statement catches that, and performs the UPDATE action.
Given that (CLIENTID,CLIENTENTRYID) is the only unique key on the table (apart from the auto_increment column, not referenced by this statement), the update action will be equivalent to this statement:
UPDATE `mytable`
SET COUNT1 = ?
, COUNT2 = ?
WHERE CLIENTID = ?
AND CLIENTENTRYID = ?
... using the values supplied in the VALUES clause of the INSERT statement.
Bottom line, there isn't an issue in anything OP showed us. The logic is sound. There is something else going on, apart from this SQL statement.
OP code shows as using scalars (and not array elements) as arguments in the bind_param call, so that whole messiness of passing by reference shouldn't be an issue.
There's not an issue with the SQL statement OP has shown, based on everything OP told us and shown us. The issue reported has to be something other than the SQL statement.
Looking at the MySQL doc, it says that given an insert statement
INSERT INTO table (a,b,c) VALUES (1,2,3) ON DUPLICATE KEY UPDATE c=c+1;
if column a and b are unique, the insert is equivalent to an update statement with a WHERE clause containing an OR instead of an AND:
UPDATE table SET c=c+1 WHERE a=1 OR b=2 LIMIT 1;
And to quote from the documentation,
If a=1 OR b=2 matches several rows, only one row is updated. In
general, you should try to avoid using an ON DUPLICATE KEY UPDATE
clause on tables with multiple unique indexes.
Hope this helps.
UPDATE:
As per further discussion, OP will consider re-visiting existing database design. OP also has another table with similar multiple unique index spec, but without the same problem by utilizing INSERT IGNORE.
I found the answer.
As everyone here correctly suggested, this was something else. For some completely bizarre reason, the button I used to open the "add new entry" somehow POST'ed to set arrived = 0 on a selected object in a table view that has nothing to do with the button.
This must have been a UI linking somewhere in my Storyboard.
I'm sorry I wasted so much of your time guys. At least I learned a little more about SQL and indexes.
i think problem is with your are using values in UPDATE COUNT1=VALUES(COUNT1),COUNT2=VALUES(COUNT2) try to use like this
ON DUPLICATE KEY UPDATE COUNT1 = $v1,COUNT2 = $v2;
I have searched around for the answer to this and have come across IGNORE and WHERE NOT EXISTS however they both seem to do slightly differently than what I am trying to accomplish. My MYSQL table appears as follows:
id(auto increment INT), charactername(VARCHAR), characterregion(VARCHAR), characterrealm(VARCHAR)
My data is retrieved from a website that returns all of the characters of a game, even the ones I already have in my database.
I wish to keep a list of all of the characters but no duplicates. My issue seems to be that I need to compare the name, realm and region of the character before deciding if it is a duplicate as the same name can appear on different region/realm combinations.
I have tried comparing all of the values of the 3 non-auto incrementing columns as follows:
REPLACE INTO characters (charactername, characterregion, characterrealm) VALUES ('Peter','AMERICA','Realm1') WHERE NOT EXISTS(SELECT * FROM characters WHERE charactername='Peter' AND characterregion='AMERICA' AND characterrealm='Realm1')
This however returns a MYSQL error as the syntax is incorrect. I have also tried INSERT IGNORE INTO... however that only seems to be checking the id value. I don't believe I need to check the id at all as I have it set to auto increment.
Any help would be greatly appreciated, I am using PHP for the other parts of this if it helps. Thanks again.
Just add a composite index on all 3 columns.
alter ignore table mytable add unique index(charactername, characterregion, characterrealm);
then do
INSERT INTO characters (charactername, characterregion, characterrealm)
VALUES ('Peter','AMERICA','Realm1')
ON DUPLICATE KEY
UPDATE
charactername='Peter1',characterregion='AMERICA1',characterrealm='Realm11'
The update will trigger only if all 3 columns are identical.Or you could do just an INSERT and it will fail if all 3 columns are identical.
I'm having a spot of trouble with a bit of code meant to find duplicates of a name along with the platform. This will also be adapted to find unique IDs later on.
So for example, if there is a server named "Apple" on the Xbox and you try to insert a record with the name "Apple" with the same platform it will reject it. However, another platform with the same name is allowed, such as "Apple" with PS3.
I've tried coming up with ideas and searching for answers, but I'm kind of in the dark as to what is the best way to go about checking for duplicates.
So far this is what I have:
$nameDuplicate_sql = $db->prepare("SELECT * FROM `servers` WHERE name=':name' AND platform=':platform'");
$nameDuplicate_sql->bindValue(':name', $name);
$nameDuplicate_sql->bindValue(':platform', $platform);
$nameDuplicate_sql->execute();
I've tried a bunch of different solutions, some from here, others from the PHP's manual and etc. None appear to work though.
I'm trying to stick with PDO, however, this is one instance where I cannot figure out where to turn. If this was in mysql_* I probably could just use mysql_affected_rows, but with PDO I have no clue. rowCount seemed promising, but it always returns 0 since this is neither an INSERT, UPDATE, or DELETE statement.
Oh, and I've tried the SQL statement in phpMyAdmin and it works; I tried it with a simple name/platform and it found rows properly.
If anyone can help me out here I'd appreciate it.
For most databases, PDOStatement::rowCount() does not return the
number of rows affected by a SELECT statement.
Instead, use PDO::query() to issue a SELECT COUNT(*) statement with the same predicates as your intended SELECT statement, then use
PDOStatement::fetchColumn() to retrieve the number of rows that will
be returned.
Your application can then perform the correct action.
Instead of checking for duplicates, why not just enforce it on the database table directly? Create a composite key that will prohibit entries being made if they are already there?
CREATE TABLE servers (
serverName varchar(50),
platform varchar(50),
PRIMARY KEY (serverName, platform)
)
This way, you will never get duplicates, and it also allows you to use the mysql insert... on duplicate key update... syntax which sounds like it might be rather handy for you.
If you already have a Primary Key on it or you don't want to make a new table, you can use the following:
ALTER TABLE servers DROP PRIMARY KEY, ADD PRIMARY KEY(serverName, platform);
Edit: A primary key is either a single row or a number of rows that have to have unique data in them. A single row cannot have the same value twice, but a composite key (which is what I am suggesting here) means that between the two columns, the same data cannot appear.
In this case, what you want to do, add in a server name and have it associated with a platform - the table will let you add in as many rows containing the same server name - as long as each one has a unique platform associated with it - and vice versa, you can have a platform listed as many times as you like, as long as all the server names are unique.
If you try to insert a record where the same servername/platform combination exists, the database simply won't let you do it. There is another golden benefit though. Due to this key constraint - mysql allows a special type of query to be used. It is the insert... on duplicate key update syntax. That means if you try to insert the same data twice (ie, database says no) you can catch it and update the row you already have in the table. For example:
You have a row with serverName=Fluffeh and it is on platform=Boosh but you don't know about it right now, so you try to insert a record with the intention of updating the server IP address.
Normally you would simply write something like this:
insert into servers (serverName, platform, IPAddress)
values ('$serverName', '$platform', '$IPAddy')
But with a nice primary key identified you can do this:
insert into servers (serverName, platform, IPAddress)
values ('$serverName', '$platform', '$IPAddy')
on duplicate key update set IPAddress='$IPAddy';
The second query will insert the row with all the data if it doesn't exist already. If it doesm, Bam! it will update the IP Address of the server which was your intention all along.
Remove the single quotes from your query on the parameter tokens... they will be quoted once they are bound... thats part of the reason for a prepared statement.
$nameDuplicate_sql = $db->prepare("SELECT * FROM `servers` WHERE name= :name AND platform= :platform");
I am running these two statements one right after another in some PHP code.
INSERT INTO input (ID) VALUES('1');
UPDATE input SET `vendor_name` = 'some name' WHERE ID=1
If the database table is empty (meaning I just truncated the table), no data is created, no warnings appear. It's as if I never executed the query.
If I then run just
INSERT INTO input (ID) VALUES('1');
On this exact same clear table, an entry is created no problem.
After that, if I again run the same INSERT/UPDATE querys
INSERT INTO input (ID) VALUES('2');
UPDATE input SET `vendor_name` = 'some name' WHERE ID=2
Then the data is created and the vendor_name set appropriately. What is going on here?? I seem to be misunderstanding something fundamental about inserting data into a database. Can I not execute statements back-to-back like this on an empty table?
To pre-empt the inevitable silly questions like 'does the column exist?', here is some extra notes:
NO warnings ever appear. This really bugs me. The INSERT/UPDATE seems to fail silently. (yes, yes, I have set error reporting on and I checked the logs)
The appropriate columns/tables/databases/permissions exist and are defined (remember the query works fine if there is an empty row in the table)
ID is the primary key. The numbers I used for IDs (1,2, whatever) do not seem to matter. I could just as well reverse them, or use 101 and 102, whatever.
Create table looks like so: CREATE TABLE IF NOT EXISTS $tablename (ID INT NOT NULL AUTO_INCREMENT PRIMARY KEY). Columns are added dynamically by users. So right now there's about 100 columns in the table ( keep in mind this shouldn't matter. I'm only trying to update one column, and that update works fine if there is data in the table)
Sneaking a Count(*) query in there reveals that the row is created, but then disappears after the Update statement. (Perhaps the row wasn't completed, or something, and there's a 'make sure the insert is finished' query I need to run?)
Try this code.... for me its works....
INSERT INTO `input` (ID) VALUES('1');
UPDATE `input` SET `vendor_name` = 'some name' WHERE ID=1
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.