Error 1062: duplicate entry in non-primary field - mysql

I have recently started to work with MySQL for my study job and now face following problem:
My predecessor created a textmining table of the following structure:
+------------+--------------+------+-----+---------+-------+
| Field | Type | Null | Key | Default | Extra |
+------------+--------------+------+-----+---------+-------+
| TokenId | int(11) | NO | PRI | 0 | |
| Value | varchar(255) | YES | | NULL | |
| Frequency | int(11) | YES | | NULL | |
| PMID | int(11) | YES | MUL | NULL | |
+------------+--------------+------+-----+---------+-------+
In the context of restructuring, I added the following column:
+------------+--------------+------+-----+---------+-------+
| NewTokenId | int(11) | YES | | NULL | |
+------------+--------------+------+-----+---------+-------+
If I now run the query:
insert into TitleToken(NewTokenId) select t.TokenId from Token as t, TitleToken as tt where t.Value = tt.Value
or even the query:
insert into TitleToken(NewTokenId) values(1);
I get following output:
ERROR 1062 (23000): Duplicate entry '0' for key 'PRIMARY'
As I said, I am relatively new to (hands-on) *SQL and it feels like a stupid mistake, but since the column NewTokenId is no primary key, not unique and even Null is YES, I thought I'd be able to insert basically anything I want.
Any hint would be appreciated... thanks in advance :)

The problem here is that you have a default value for the primary key "TokenID", if you do not insert a value for the key in your insert statement the system will automatically insert 0. However, if there is another tuple with the same value for this attribute (which is probable because the default is 0) you will get that error.

You are attempting to perform an insert into a table without providing a unique value for TokenId. By default, according to the table description, TokenId defaults to 0, you cannot have multiple identical values in that column.

Related

I thought auto_increment prevents duplicates entries?

I am getting duplicate entry error for key 'primary' when trying to insert values and I can't get past it. I added auto_increment to the integer part of the composite key (term_taxonomy_id). Isn't auto_increment supposed to resolve duplicate entries in these situations by incrementing the error-causing record on the fly?
+------------------+---------------------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+------------------+---------------------+------+-----+---------+----------------+
| object_id | varchar(50) | NO | PRI | NULL | |
| term_taxonomy_id | bigint(20) unsigned | NO | PRI | NULL | auto_increment |
| term_order | int(11) | NO | | 0 | |
+------------------+---------------------+------+-----+---------+----------------+
https://dev.mysql.com/doc/refman/8.0/en/example-auto-increment.html says:
When you insert any other value into an AUTO_INCREMENT column, the column is set to that value and the sequence is reset so that the next automatically generated value follows sequentially from the largest column value.
So the auto-increment column generates a new, unique value only if you insert NULL or 0. If you specify a nonzero integer value, you override the auto-increment, and MySQL trusts that you are inserting the value you want. But that means you take responsibility for ensuring the values you insert are unique.

MySQL - insert rows in one table and then update another with the auto increment ID

I have 2 tables called applications and filters. The structure of the tables are as follows:
mysql> DESCRIBE applications;
+-----------+---------------------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+-----------+---------------------+------+-----+---------+----------------+
| id | tinyint(3) unsigned | NO | PRI | NULL | auto_increment |
| name | varchar(255) | NO | | NULL | |
| filter_id | int(3) | NO | | NULL | |
+-----------+---------------------+------+-----+---------+----------------+
3 rows in set (0.01 sec)
mysql> DESCRIBE filters;
+----------+----------------------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+----------+----------------------+------+-----+---------+----------------+
| id | smallint(5) unsigned | NO | PRI | NULL | auto_increment |
| name | varchar(100) | NO | | NULL | |
| label | varchar(255) | NO | | NULL | |
| link | varchar(255) | NO | | NULL | |
| anchor | varchar(100) | NO | | NULL | |
| group_id | tinyint(3) unsigned | NO | MUL | NULL | |
| comment | varchar(255) | NO | | NULL | |
+----------+----------------------+------+-----+---------+----------------+
7 rows in set (0.02 sec)
What I want to do is select all the records in applications and make a corresponding record in filters (so that filters.name is the same as applications.name). When the record is inserted in filters I want to get the primary key (filters.id) of the newly inserted record - which is an auto increment field - and update applications.filter_id with it. I should clarify that applications.filter_id is a field I've created for this purpose and contains no data at the moment.
I am a PHP developer and have written a script which can do this, but want to know if it's possible with a pure MySQL solution. In pseudo-code the way my script works is as follows:
Select all the records in applications
Do a foreach loop on (1)
Insert a record in filters (filters.name == applications.name)
Store the inserted ID (filters.id) to a variable and then update applications.filter_id with the variable's data.
I'm unaware of how to do the looping (2) and storing the auto increment ID (4) in MySQL.
I have read about Get the new record primary key ID from mysql insert query? so am aware of LAST_INSERT_ID() but not sure how to reference this in some kind of "loop" which goes through each of the applications records.
Please can someone advise if this is possible?
I don't think this is possible to do this with only one request to mysql.
But, i think this is a good use case for mysql triggers.
I think you should write it like this :
CREATE TRIGGER after_insert_create_application_filter AFTER INSERT
ON applications FOR EACH ROW
BEGIN
INSERT INTO filters (name) VALUES (NEW.name);
UPDATE applications SET filter_id = LAST_INSERT_ID() WHERE id = NEW.id;
END
This trigger is not tested but you should understand the way to write it.
If you don't know mysql triggers, you can read this part of the documentation.
This isn't an answer to your question, more a comment on your database design.
First of all, if the name field needs to contain the same information, they should be the same type and size (varchar(255))
Overall though, I think the schema you're using for your tables is wrong. Your description says that each record in applications can only hold one filter_id. If that is the case, there's no point in using two separate tables.
If there is a chance that there will be a many-to-one relationship, link the records via the relevant primary key. If multiple records in application can relate to a single filter, store filters.id in the applications table. If there are multiple filters for a single application, store applications.id in the filters table.
If there is a many-to-many relationship, create another table to store it:
CREATE TABLE `application_filters_mappings` (
`id` int(10) unsigned NOT NULL AUTO_INCREMENT,
`application_id` int(10) unsigned NOT NULL,
`filters_id` int(10) unsigned NOT NULL,
PRIMARY KEY (`id`)
);

ERROR 1054 (42S22): Unknown column 'marks' in 'field list'

This is a very simple MySQL query.
INSERT INTO users_questions (user_id, question_id, mcopt_id,timestamp)
VALUES (50053, 875, 3092, '2015-08-22 18:01:44');
When I use it I get
ERROR 1054 (42S22): Unknown column 'marks' in 'field list'
marks is a column in the same table whose default value is set to NULL and in the above query I don't even use the column name marks.
So why exactly am i getting the error?
Structure of table:
+-------------+-----------+------+-----+-------------------+-------+
| Field | Type | Null | Key | Default | Extra |
+-------------+-----------+------+-----+-------------------+-------+
| user_id | int(11) | NO | PRI | NULL | |
| question_id | int(11) | NO | PRI | NULL | |
| mcopt_id | int(11) | NO | | NULL | |
| timestamp | timestamp | NO | | CURRENT_TIMESTAMP | |
| marks | int(11) | NO | | NULL | |
+-------------+-----------+------+-----+-------------------+-------+
Just to make it clear I also get the error when I provide the value of marks
INSERT INTO users_questions (user_id, question_id, mcopt_id, timestamp, marks) VALUES (50053, 875, 3094, '2015-08-22 19:15:07', 1)
`
Sometimes, when you implement wrong trigger, it happens.
So just drop your trigger by using:
DROP TRIGGER [IF EXISTS] [schema_name.]trigger_name
and it actually worked in my Mysql case. Maybe helpful for some of you.
A:
create table users_questions2
( user_id int not null,
question_id int not null,
mcopt_id int not null,
timestamp timestamp not null,
marks int not null
);
describe users_questions2;
+-------------+-----------+------+-----+-------------------+-----------------------------+
| Field | Type | Null | Key | Default | Extra |
+-------------+-----------+------+-----+-------------------+-----------------------------+
| user_id | int(11) | NO | | NULL | |
| question_id | int(11) | NO | | NULL | |
| mcopt_id | int(11) | NO | | NULL | |
| timestamp | timestamp | NO | | CURRENT_TIMESTAMP | on update CURRENT_TIMESTAMP |
| marks | int(11) | NO | | NULL | |
+-------------+-----------+------+-----+-------------------+-----------------------------+
INSERT INTO users_questions2 (user_id, question_id, mcopt_id, timestamp) VALUES (50053, 875, 3092, '2015-08-22 18:01:44');
Error Code: 1364. Field 'marks' doesn't have a default value 0.047 sec
INSERT INTO users_questions2 (user_id, question_id, mcopt_id, timestamp,marks) VALUES (50053, 875, 3092, '2015-08-22 18:01:44',1);
-- 1 row(s) affected
INSERT INTO users_questions2 (user_id, question_id, mcopt_id, timestamp,marks) VALUES (50053, 875, 3092, '2015-08-22 18:01:44',null);
Error Code: 1048. Column 'marks' cannot be null 0.000 sec
B:
drop table users_questions2;
create table users_questions2
( user_id int null,
question_id int null,
mcopt_id int null,
timestamp timestamp null,
marks int null
);
describe users_questions2;
+-------------+-----------+------+-----+---------+-------+
| Field | Type | Null | Key | Default | Extra |
+-------------+-----------+------+-----+---------+-------+
| user_id | int(11) | YES | | NULL | |
| question_id | int(11) | YES | | NULL | |
| mcopt_id | int(11) | YES | | NULL | |
| timestamp | timestamp | YES | | NULL | |
| marks | int(11) | YES | | NULL | |
+-------------+-----------+------+-----+---------+-------+
INSERT INTO users_questions2 (user_id, question_id, mcopt_id, timestamp) VALUES (50053, 875, 3092, '2015-08-22 18:01:44');
1 row(s) affected
So the only way I can get my describe table to look like yours is if they are not null columns (section A above).
Which means your columns do not accept nulls.
Edit:
show variables like "%version%";
+-------------------------+------------------------------+
| Variable_name | Value |
+-------------------------+------------------------------+
| innodb_version | 5.6.24 |
| protocol_version | 10 |
| slave_type_conversions | |
| version | 5.6.24-log |
| version_comment | MySQL Community Server (GPL) |
| version_compile_machine | x86_64 |
| version_compile_os | Win64 |
+-------------------------+------------------------------+
Column marks is defined as not nullable with default value NULL. I suppose that is the problem. You should assign a value in the insert or change default value
The table you are reference in the query does not have a column named marks. First check that you have to correct query which failed and not looking at a different query. Specially when the error message say the table doesn't have a marks column and your query doesn't even have this column written then you are looking at the wrong query. Then check the table you are using and that it has a column named marks. Your error message has nothing to do about NULL or NOT NULL.
I found a similar problem with the command:
INSERT INTO `rel_artsizeprice` (`art_id`, `artsize_id`, `price_tax`) VALUES (1, 3, 2.5);
ERROR 1054 (42S22): Unknown column ' 2.5' in 'field list'
If I delete the space before 2.5, it works:
INSERT INTO `rel_artsizeprice` (`art_id`, `artsize_id`, `price_tax`) VALUES (1, 3,2.5);
Query OK, 1 row affected (0.06 sec)
I a large list of such insert values there are only some places, which generates an error. So I think, that there is an error in the source of the commandline tool (readline or mysql).
I used:
mysql --version
mysql Ver 15.1 Distrib 10.0.26-MariaDB, for debian-linux-gnu (x86_64) using readline 5.2
The table You had created will not accept the Null value you have to define the value of marks. It cannot be null probably you have used the not null. if you want your column to be null better use simply null.
One more technical Mistake you are doing here is defining two primary keys. A table should only have one primary key it can have enormous unique keys but primary key should only be one.
You must use single quote marks before and after each record.
INSERT INTO users_questions (user_id, question_id, mcopt_id,timestamp)
VALUES ('50053', '875', '3092', '2015-08-22 18:01:44');

on duplicate key update result affecting all the rows of the table

I have a table of this structure:
mysql> desc securities;
+-----------------+-------------+------+-----+---------+-------+
| Field | Type | Null | Key | Default | Extra |
+-----------------+-------------+------+-----+---------+-------+
| sym | varchar(19) | NO | PRI | | |
| bqn | int(11) | YES | | NULL | |
| sqn | int(11) | YES | | NULL | |
| tqn | int(11) | YES | | NULL | |
+-----------------+-------------+------+-----+---------+-------+
4 rows in set (0.01 sec)
I am trying to do a select and an update within the same query, so the reason I have chosen
insert into securities (sym, bqn, sqn , tqn) values('ANK', 50,0,1577798)
on duplicate key update bqn=bqn+50 , sqn=sqn+0 , tqn=tqn+1577798;
When I ran the above I observed it is in fact changing the values for all the other rows also.
Is this behaviour expected? I am using MySQL Database.
Your fiddle is missing the key, and the INSERT statement in the right panel (where it does not belong in the first place) is using different column names … *sigh*
Define the symbol column as PRIMARY KEY – and use the VALUES() syntax to get the values to add in the ON UPDATE part, so that you don’t have to repeat them every single time:
insert into securities
(symbol, buyerquan, sellerquan , totaltradedquan)
values('BANKBARODA', 73, 0, 4290270)
on duplicate key update
buyerquan=buyerquan+VALUES(buyerquan),
sellerquan=sellerquan+VALUES(sellerquan),
totaltradedquan=totaltradedquan+VALUES(totaltradedquan);
Works perfectly fine, result values are as to be expect from the input: http://sqlfiddle.com/#!2/21638f/1

Can a primary key be empty? If yes why did this alter cause this result?

I have the following table:
mysql> DESC my_contacts;
+----------+-------------+------+-----+---------+-------+
| Field | Type | Null | Key | Default | Extra |
+----------+-------------+------+-----+---------+-------+
| id | varchar(20) | NO | PRI | | |
| location | varchar(20) | YES | | NULL | |
| city | varchar(20) | YES | | NULL | |
| state | varchar(2) | YES | | NULL | |
+----------+-------------+------+-----+---------+-------+
4 rows in set (0.01 sec)
If I do a select all I get:
mysql> SELECT * FROM my_contacts;
+----+--------------+------+-------+
| id | location | city | state |
+----+--------------+------+-------+
| 1 | Chester,NJ | NULL | NULL |
| 2 | Katy,TX | NULL | NULL |
| 3 | San Mateo,CA | NULL | NULL |
+----+--------------+------+-------+
3 rows in set (0.00 sec)
I run the following command:
INSERT INTO my_contacts (city,state)
VALUES
(SUBSTRING_INDEX(location,',',1),RIGHT(location,2));
My purpose was to populate the columns city and state with the part before the comma and the part after the comma from the location column.
But the following happened to my table:
mysql> INSERT INTO my_contacts (city,state)
-> VALUES
-> (SUBSTRING_INDEX(location,',',1),RIGHT(location,2));
Query OK, 1 row affected (0.02 sec)
mysql> SELECT * FROM my_contacts;
+----+--------------+------+-------+
| id | location | city | state |
+----+--------------+------+-------+
| | NULL | NULL | NULL |
| 1 | Chester,NJ | NULL | NULL |
| 2 | Katy,TX | NULL | NULL |
| 3 | San Mateo,CA | NULL | NULL |
+----+--------------+------+-------+
4 rows in set (0.00 sec)
I get a record and the id which is the primary key is empty. How is this possible?
I mean it is not NULL but a primary key is not supposed to be empty either right?
You defined your id field as a varchar, which is a dumb idea when you're using it to store integers. an empty field is NOT null. a zero-length string is still a valid string, and therefore a valid id value as far as your table is concerned. Try inserting ANOTHER blank string and you'll get a primary key violation:
INSERT INTO yourtable (id) VALUES (''); // will not work
The id field should be an int type. That'd disallow "empty" values.
primary keys are unique so if you alter the table, then the second row will attempt to add an empty value and fail. as a result, it will attempt the next possible value. If you want the first value not to be empty, you can set a default value.
It's not empty. It's probably an empty string. Note that the datatype is varchar(20).
Well, you didn't assign a value to the primary key field, so the default is NULL.
.
You want to modify the table so the primary key is auto_increment.
You can use a varchar as a foreign key related to another database table, but if you wish to use it as a numerical key, you should utilize a numerical data type such as int.
I know this doesn't answer the precise question regarding the primary key, but as your question does point out the fact you are also having issues parsing out the city and state from your location column, here's the query you would want to use (note you want an UPDATE to modify existing rows, not an INSERT which will add new rows rather than columns):
UPDATE my_contacts
SET
city = substr(location, 1, locate(',', location) - 1),
state = substr(location, locate(',', location) + 1);