问题
I am trying to run a query so that it will insert or update on duplicate. I am using a unique index for the duplicate but I cannot seem to get it to work. It still adds new records. Hoping some fresh eyes can point out my issue. Thanks.
This is my schema
CREATE TABLE IF NOT EXISTS `pricing_puchasing` (
`custno` varchar(6) DEFAULT NULL COMMENT 'customer code',
`recipe` varchar(15) DEFAULT NULL,
`item` varchar(120) NOT NULL COMMENT 'Item Code from dProduce',
`unit_weight` double(12,4) DEFAULT NULL,
`case_cost` double(12,4) DEFAULT NULL COMMENT 'Projected cost of item',
`cost_per_lb` double(12,4) NOT NULL,
`projected_price` float(12,3) DEFAULT NULL COMMENT 'projected Price',
`projected_margin` float(12,3) DEFAULT NULL COMMENT 'Projected Margin',
`trend` tinyint(1) DEFAULT NULL COMMENT 'Trend status 1=up, 0=down',
`note` varchar(255) DEFAULT NULL COMMENT 'Note about the data',
`week_of` date NOT NULL COMMENT 'Week of this data',
`approved` tinyint(1) DEFAULT NULL COMMENT 'approval flag',
`last_edited_from` varchar(20) NOT NULL COMMENT 'identifier to know where it was last saved from',
`saved_at` datetime NOT NULL COMMENT 'Date time of save/update',
`saved_by` int(11) NOT NULL COMMENT 'Created by user ID'
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='Stores pricing purchasing data';
ALTER TABLE `pricing_puchasing`
ADD UNIQUE KEY `custno_recipe_item_week_of` (`custno`,`recipe`,`item`,`week_of`), ADD KEY `custno` (`custno`);
This is the query I am testing:
INSERT INTO pricing_puchasing
(recipe,item,unit_weight,case_cost,cost_per_lb,trend,note,week_of,saved_at,saved_by,approved,last_edited_from)
VALUES
('APPLEGRRAW','APPLEGRRAW',40.00,100.01,2.50,0,'','2014-07-28',NOW(),1,NULL,'purchasing')
ON DUPLICATE KEY UPDATE
unit_weight=40.00,case_cost=100.01,cost_per_lb=2.50,trend=0,note='',saved_at=NOW(),saved_by=1,approved=NULL,last_edited_from='purchasing'
EDIT I fixed the issue with custno missing but I still am having issue with it inserting duplicates. I created a sqlfiddle. This time I am testing with 2 NULL values and still a no go... Is it my schema or is this still an issue with my query?
回答1:
A NULL
value is not consider to be "unique". The first column in the unique index is custno
, you aren't providing a value for that column in the INSERT, so the default value of NULL is used as the value for that column.
Because of the NULL value is not considered to be unique, the INSERT will not throw a duplicate key exception.
Try it with a non-NULL value for the custno column.
Also, you can use the special VALUES()
function in the UPDATE portion of the statement, to reference the value that was supplied in the INSERT.
ON DUPLICATE KEY UPDATE
unit_weight=VALUES(unit_weight),case_cost=VALUES(case_cost)
http://dev.mysql.com/doc/refman/5.5/en/miscellaneous-functions.html#function_values
回答2:
The UNIQUE constraint doesn't count NULLs as duplicates. That is, you can have multiple rows with a NULL as one or more columns of a unique key.
Your INSERT statement doesn't specify a value for custno
, as @Fabricator points out in a comment. The default for the custno
column is NULL, so the INSERT doesn't violate the unique constraint.
回答3:
The problem is that your table doesn't have a primary key and your query also doesn't specify a key. Suppose custno is the primary key, you can use mysql replace statement instead of update on duplicate key in an insert statement. In this case it will be
REPLACE INTO pricing_puchasing
(custno,recipe,item,unit_weight,case_cost,cost_per_lb,trend,note,week_of,saved_at,saved_by,approved,last_edited_from)
VALUES
('123','bbfAPPLEGRRAW','APPLEGRRAW',40.00,100.01,2.50,0,'','2014-07-28',NOW(),1,NULL,'purchasing');
回答4:
As mentioned previously (spencer7593 et al), null != null, so nullable fields don't work well in unique keys. However, upserts can be done simply with insert on duplicate key update statements if you add MySQL's generated stored columns or MariaDB persistent virtual columns to apply the uniqueness constraint on the nullable fields indirectly.
e.g.
CREATE TABLE IF NOT EXISTS `pricing_puchasing` ( `custno` varchar(6) DEFAULT NULL COMMENT 'customer code', `vcustno` varchar(6) AS (COALESCE(custno, '')) STORED, `recipe` varchar(15) DEFAULT NULL, `vrecipe` varchar(15) AS (COALESCE(recipe, '')) STORED, `item` varchar(120) NOT NULL COMMENT 'Item Code from dProduce', `unit_weight` double(12,4) DEFAULT NULL, `case_cost` double(12,4) DEFAULT NULL COMMENT 'Projected cost of item', `cost_per_lb` double(12,4) NOT NULL, `projected_price` float(12,3) DEFAULT NULL COMMENT 'projected Price', `projected_margin` float(12,3) DEFAULT NULL COMMENT 'Projected Margin', `trend` tinyint(1) DEFAULT NULL COMMENT 'Trend status 1=up, 0=down', `note` varchar(255) DEFAULT NULL COMMENT 'Note about the data', `week_of` date NOT NULL COMMENT 'Week of this data', `approved` tinyint(1) DEFAULT NULL COMMENT 'approval flag', `last_edited_from` varchar(20) NOT NULL COMMENT 'identifier to know where it was last saved from', `saved_at` datetime NOT NULL COMMENT 'Date time of save/update', `saved_by` int(11) NOT NULL COMMENT 'Created by user ID' ) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='Stores pricing purchasing data'; ALTER TABLE `pricing_puchasing` ADD UNIQUE KEY `custno_recipe_item_week_of` (`vcustno`,`vrecipe`,`item`,`week_of`), ADD KEY `custno` (`custno`);
For MariaDB replace STORED with PERSISTENT, indexes require persistence.
MySQL Generated Columns MariaDB Virtual Columns
来源:https://stackoverflow.com/questions/24978541/mysql-update-on-duplicate-key-only-inserting