What causes duplicate PKs in MySQL? - mysql

I encountered this quite a few times so far, but still don't understand it (my MySQL internals skills are equal to none).
I know it's probably a PEBKAC but trying to replicate the behavior manually ends up with an error (autoincrement).
CREATE TABLE `foo_bar` (
`id` int(12) unsigned NOT NULL AUTO_INCREMENT,
`user_id` int(12) unsigned DEFAULT NULL,
`order_id` int(12) unsigned DEFAULT NULL,
`email_address` varchar(50) DEFAULT NULL,
`mobile_number` varchar(20) DEFAULT NULL,
`message` longtext NOT NULL,
`message_received` int(12) unsigned DEFAULT NULL,
`failed_to_send` tinyint(1) unsigned DEFAULT NULL,
`fraudulent_activity` tinyint(1) unsigned DEFAULT NULL,
PRIMARY KEY (`id`)
) ENGINE=ARCHIVE DEFAULT CHARSET=utf8;

When your program inserts a row in the database, it should provide NULL as the value for auto-incremented field:
CREATE TABLE `customers` (
`id` INT( 11 ) NOT NULL AUTO_INCREMENT PRIMARY KEY ,
`name` VARCHAR( 128 ) NOT NULL
) ENGINE = MYISAM ;
INSERT INTO `customers` ( `id` , `name` )
VALUES ( NULL , 'Customer 1' ), ( NULL , 'Customer 2' );
If you try to insert a specific value in id field, MySQL will give an error:
SQL query:
INSERT INTO `customers` ( `id` , `name` )
VALUES ( '1', 'Customer 3' );
MySQL said:
#1062 - Duplicate entry '1' for key 'PRIMARY'

Although the answer to "what caused this" didn't come up, REPAIR TABLE fixes the problem.
Answering this so I can close the question.

Related

How do I INSERT into a database with a primary autoincrement key?

So I have a table that is laid out according to:
CREATE TABLE `dealerships` (
`dealership_id` BIGINT(20) UNSIGNED NOT NULL,
`zone` CHAR(200) NULL DEFAULT NULL,
`phone` BIGINT(20) UNSIGNED NOT NULL,
`fax` BIGINT(20) UNSIGNED NOT NULL,
`name` CHAR(200) NULL DEFAULT NULL,
`address1` CHAR(200) NULL DEFAULT NULL,
`address2` CHAR(200) NULL DEFAULT NULL',
`servicephone` BIGINT(20) UNSIGNED NULL DEFAULT NULL,
`timezone` CHAR(20) NULL DEFAULT NULL,
PRIMARY KEY (`dealership_id`)
)
COMMENT='This stores dealership information. '
COLLATE='utf8_general_ci'
ENGINE=InnoDB;
Now when I insert with
INSERT INTO dealerships (dealership_id, ~the rest~), VALUES( NULL, ~values);
This returns an error that dealership_id cannot be NULL error 1048.
INSERT INTO dealerships (dealership_id, ~the rest~), VALUES(0, ~values);
This returns an error that dealership_id already exists for value 0.
INSERT INTO dealerships (dealership_id, ~the rest~), VALUES(default, ~values);
This returns an error that dealership_id has no default value error 1364.
When I simply say screw it, and ommit dealership_id
INSERT INTO dealerships (~the rest~), VALUES(~values);
I get the error that a value must be specified for dealership_id.
Every-time I've worked with autoincrement primary keys. Normally inserting NULL would work for the index to do the auto-magical things for me. What is happening??
Platform Specific Information:
MariaDB10.1.18 x64
Windows Server 2012 R2
For create add AUTO_INCREMENT
CREATE TABLE `dealerships` (
`dealership_id` BIGINT(20) UNSIGNED NOT NULL AUTO_INCREMENT,
`zone` CHAR(200) NULL DEFAULT NULL,
`phone` BIGINT(20) UNSIGNED NOT NULL,
`fax` BIGINT(20) UNSIGNED NOT NULL,
`name` CHAR(200) NULL DEFAULT NULL,
`address1` CHAR(200) NULL DEFAULT NULL,
`address2` CHAR(200) NULL DEFAULT NULL',
`servicephone` BIGINT(20) UNSIGNED NULL DEFAULT NULL,
`timezone` CHAR(20) NULL DEFAULT NULL,
PRIMARY KEY (`dealership_id`)
)
COMMENT='This stores dealership information. '
COLLATE='utf8_general_ci'
ENGINE=InnoDB;
and for insert don't insert the key (is automatically create by auto increment)
insert into `dealerships` (
`zone`,
`phone`,
`fax` ,
`name`,
`address1`,
`address2`',
`servicephone` ,
`timezone`
) values (
'vale_zone',
1,
2 ,
'val_name',
'val_address1',
'val_address2',
3 ,
'val_timezone'
)
To insert a field with auto increment property, use ID int NOT NULL AUTO_INCREMENT in the create table.
CREATE TABLE `dealerships` (
`dealership_id` INT NOT NULL AUTO_INCREMENT,
`zone` CHAR(200) NULL DEFAULT NULL,
`phone` BIGINT(20) UNSIGNED NOT NULL,
`fax` BIGINT(20) UNSIGNED NOT NULL,
`name` CHAR(200) NULL DEFAULT NULL,
`address1` CHAR(200) NULL DEFAULT NULL,
`address2` CHAR(200) NULL DEFAULT NULL',
`servicephone` BIGINT(20) UNSIGNED NULL DEFAULT NULL,
`timezone` CHAR(20) NULL DEFAULT NULL,
PRIMARY KEY (`dealership_id`)
)
COMMENT='This stores dealership information. '
COLLATE='utf8_general_ci'
ENGINE=InnoDB;
After, you have two solutions to insert data.
Solution 1
INSERT INTO dealerships(zone, phone, fax, name) VALUES('zone1', '00000', '00000', 'name1')
In this case I chossen to add data in only few columns (add the others on the wame way).
Solution 2
INSERT INTO dealerships SET zone = 'zone1', phone = '0000', name = 'Eddy'
Here, I used the field SET field = value, field2 = value2.
As you can see I didn't added any reference to the ID. Normal, the field is AUTO_INCREMENT mode, and Mysql (or tothers SGBD) will create automatically a value.
Of course, you can force the value:
INSERT INTO dealerships SET dealership_id = 10, zone = 'zone1', phone = '0000', name = 'Eddy'
INSERT INTO dealerships(dealership_id, zone, phone, fax, name) VALUES(9, 'zone1', '00000', '00000', 'name1')
http://www.w3schools.com/sql/sql_insert.asp
About your errors
Normal. You specified NOT NULL
Normal, there is already a record for the value 0 (check your database)
Normal. You can't use default. This is a constant with his own value (1364).
Normal, the field as if can't be ommited
The only way to does not have this issue is to remove completely the reference of the ID field. Use the solution described :)
Georges explained it all for you. If you want to add auto increment to table just run this sql statement
ALTER TABLE dealerships MODIFY COLUMN dealership_id BIGINT(20) UNSIGNED NOT NULL PRIMARY KEY AUTO_INCREMENT;
This will add the auto increment property on the column dealership_id. And if you want to change auto increment start value run this (Change 100 to your start value)
ALTER TABLE dealerships AUTO_INCREMENT=100;

Keeping last seen values in a summary table

I have two tables:
parameters keeps all the para_ids and their names and is always updated to have all parameters in it.
CREATE TABLE `parameters` (
`para_id` int(10) unsigned NOT NULL AUTO_INCREMENT,
`name` varchar(255) NOT NULL DEFAULT '',
PRIMARY KEY (`para_id`),
UNIQUE KEY `idx_parameters_name` (`name`)
) ENGINE=InnoDB;
processing is holding a chunk of data every 5 minutes.
CREATE TABLE `processing` (
`id` bigint(20) unsigned NOT NULL AUTO_INCREMENT,
`t_ns` bigint(20) unsigned NOT NULL DEFAULT '0',
`para_id` int(10) unsigned NOT NULL DEFAULT '0',
`value` varchar(1024) NOT NULL DEFAULT '',
`isanchor` tinyint(1) NOT NULL DEFAULT '0',
PRIMARY KEY (`id`),
KEY `data` (`para_id`,`t_ns`)
) ENGINE=InnoDB;
I want to keep a table actual_values with the last seen values that each parameter (if it occurred in processing) had. The para_ids are updated with an INSERT IGNORE before the update. Currently I have those queries:
INSERT IGNORE INTO actual_values (para_id) (SELECT DISTINCT para_id FROM parameters);
UPDATE actual_values a
JOIN processing p ON a.para_id = p.para_id
SET a.value = (SELECT p.value FROM processing p WHERE a.para_id = p.para_id ORDER BY t_ns DESC LIMIT 1);
I feel like this is not the optimal way to go, it takes quite long. Do you guys have better suggestions?

MySQL use separate indices for JOIN and GROUP BY

I am trying to execute following query
SELECT
a.sessionID AS `sessionID`,
firstSeen, birthday, gender,
isAnonymous, LanguageCode
FROM transactions AS trx
INNER JOIN actions AS a ON a.sessionID = trx.SessionID
WHERE a.ActionType = 'PURCHASE'
GROUP BY trx.TransactionNumber
Explain provides the following output
1 SIMPLE trx ALL TransactionNumber,SessionID NULL NULL NULL 225036 Using temporary; Using filesort
1 SIMPLE a ref sessionID sessionID 98 infinitiExport.trx.SessionID 1 Using index
The problem is that I am trying to use one field for join and different field for GROUP BY.
How can I tell MySQL to use different indices for same table?
CREATE TABLE `transactions` (
`SessionID` varchar(32) NOT NULL DEFAULT '',
`date` datetime DEFAULT NULL,
`TransactionNumber` varchar(32) NOT NULL DEFAULT '',
`CustomerECommerceTrackID` int(11) DEFAULT NULL,
`SKU` varchar(45) DEFAULT NULL,
`AmountPaid` double DEFAULT NULL,
`Currency` varchar(10) DEFAULT NULL,
`Quantity` int(11) DEFAULT NULL,
`Name` tinytext NOT NULL,
`Category` varchar(45) NOT NULL DEFAULT '',
`customerInfoXML` text,
`id` int(11) unsigned NOT NULL AUTO_INCREMENT,
PRIMARY KEY (`id`),
KEY `TransactionNumber` (`TransactionNumber`),
KEY `SessionID` (`SessionID`)
) ENGINE=InnoDB AUTO_INCREMENT=212007 DEFAULT CHARSET=utf8;
CREATE TABLE `actions` (
`id` int(11) unsigned NOT NULL AUTO_INCREMENT,
`sessionActionDate` datetime DEFAULT NULL,
`actionURL` varchar(255) DEFAULT NULL,
`sessionID` varchar(32) NOT NULL DEFAULT '',
`ActionType` varchar(64) DEFAULT NULL,
`CustomerID` int(11) DEFAULT NULL,
`IPAddressID` int(11) DEFAULT NULL,
`CustomerDeviceID` int(11) DEFAULT NULL,
`customerInfoXML` text,
PRIMARY KEY (`id`),
KEY `ActionType` (`ActionType`),
KEY `CustomerDeviceID` (`CustomerDeviceID`),
KEY `sessionID` (`sessionID`)
) ENGINE=InnoDB AUTO_INCREMENT=15042833 DEFAULT CHARSET=utf8;
Thanks
EDIT 1: My indexes were broken, I had to add (SessionID, TransactionNumber) index to transactions table, however now, when I try to include trx.customerInfoXML table mysql stops using index
EDIT 2 Another answer does not really solved my problem because it's not standard sql syntax and generally not a good idea to force indices.
For ORM users such syntax is a unattainable luxury.
EDIT 3 I updated my indices and it solved the problem, see EDIT 1

Getting a duplicate key error in MYSQL. No duplicate found

I have a table. (Code taken from table generation code, I did not write this)
DROP TABLE IF EXISTS `CatalogueBasket`;
CREATE TABLE `CatalogueBasket` (
`ID` int(11) NOT NULL auto_increment,
`Shopper` char(35) NOT NULL default '',
`ItemLink` int(11) NOT NULL default '0',
`Quantity` int(11) NOT NULL default '0',
`Created` datetime NOT NULL default '0000-00-00 00:00:00',
`ExpectedDelivery1` datetime default NULL,
`ExpectedDelivery2` datetime default NULL,
`Comments` char(255) default NULL,
`Status` int(10) unsigned default NULL,
`QuantityShipped` int(10) unsigned default NULL,
`HarmonyNumber` int(10) unsigned default NULL,
`StartDate` datetime default NULL,
KEY `ID` (`ID`),
KEY `Shopper` (`Shopper`),
KEY `ItemLink` (`ItemLink`),
KEY `Quantity` (`Quantity`),
KEY `Created` (`Created`)
) TYPE=MyISAM;
When trying to insert a new Row at the end of this table I am getting the following message.
Duplicate entry '116604' for key 1
The insert statement is:
INSERT INTO CatalogueBasket (Shopper,ItemLink,Quantity,Created, Status, StartDate)
VALUES ('0.80916300 1338507348',58825,1,'2012-06-01 09:58:23', 0, '0-0-0')
I'm assuming it is talking about the ID column.
If I run the following query I get 116603 as the last key
SELECT * FROM `CatalogueBasket` order by ID desc limit 1
Any insight / help into this is appreciated.

mySQL view for two different tables?

I've a massive problem creating a view in mySQL:
Table A in database DB1:
CREATE TABLE `a` (
`id` INT(10) UNSIGNED NOT NULL AUTO_INCREMENT COMMENT 'internal ID',
`account` VARCHAR(10) NOT NULL DEFAULT '0',
`filename` VARCHAR(50) NOT NULL,
`filesize` BIGINT(15) NOT NULL DEFAULT '0'
PRIMARY KEY (`id`)
)
ENGINE=InnoDB
Table B in database DB2:
CREATE TABLE `b` (
`archive_id` INT(10) UNSIGNED NULL AUTO_INCREMENT,
`archive_datetime` DATETIME,
`id` INT(10) UNSIGNED NOT NULL,
`account` VARCHAR(10) NOT NULL DEFAULT '0',
`filename` VARCHAR(50) NOT NULL,
`filesize` BIGINT(15) NOT NULL DEFAULT '0'
PRIMARY KEY (`archive_id`)
)
ENGINE=Archive
Entries from table A are automatically transfered to table B via trigger if BEFORE DELETE.
I need a view that gives me all entries from table a and table b as if they were still in one table of the same database. Columns archive_id and archive_datetime can be ignored in the view as they are not needed for this scenario.
You could use UNION:
SELECT * FROM a UNION SELECT * FROM b;
You just have to replace * with the desired table columns.
SELECT id, account, filename, filesize FROM a UNION ALL SELECT id, account, filename, filesize FROM b
Surely I must be missing something?