MYSQL On Duplicate Error - php

My problem:
Error: Duplicate entry '2' for key 'cnt_2'
My table:
CREATE TABLE UploadLog(
id int(11) NOT NULL AUTO_INCREMENT,
date text NOT NULL DEFAULT '',
cnt int(11) NOT NULL DEFAULT 0,
UNIQUE INDEX (id, cnt),
PRIMARY KEY (id)
)
My php code:
$date1=date("Y-m-d");
$sql = "SELECT * FROM UploadLog WHERE date='$date1'";
$result = $conn->query($sql);
$row = $result->fetch_assoc();
$dateindb=$row["cnt"];
if ($dateindb==0) {$dateindb=1;};
$sql = "INSERT INTO UploadLog (date, cnt) VALUES ('$date1', '$dateindb') ON DUPLICATE KEY UPDATE date=date, cnt=cnt+1";
if (mysqli_query($conn, $sql)) {} else {echo mysqli_error($conn)};
Data in MYSQL table:
+------+------------+-----+
| id | date | cnt |
+------+------------+-----+
| 1 | 2015-04-16 | 3 |
| 2 | 2015-04-17 | 2 |
| 3 | 2015-04-18 | 1 |
+------+------------+-----+
Current date = 2015-04-18.
Edited:
Command:
DESCRIBE DateLog
+-------+---------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+-------+---------+------+-----+---------+----------------+
| id | int(11) | NO | PRI | NULL | auto_increment |
| date | text | NO | | NULL | |
| cnt | int(11) | NO | UNI | 0 | |
+-------+---------+------+-----+---------+----------------+
Command:
SHOW CREATE TABLE UploadLog
UploadLog | CREATE TABLE `UploadLog` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`date` text NOT NULL,
`cnt` int(11) NOT NULL DEFAULT '0',
PRIMARY KEY (`id`),
UNIQUE KEY `id` (`id`),
UNIQUE KEY `cnt_2` (`cnt`),
KEY `cnt` (`cnt`),
KEY `id_2` (`id`),
KEY `cnt_3` (`cnt`)
) ENGINE=InnoDB AUTO_INCREMENT=6 DEFAULT CHARSET=latin1

I cannot explain where the error come from, but I expect, it is caused by different MySQL versions.
But first off all I would recommend to change the date column from text to char(10). This is because the content have a very defined length.
After that the table definition will look like this:
CREATE TABLE DateLog
(
id INT(11) NOT NULL AUTO_INCREMENT,
date CHAR(10) NOT NULL,
cnt INT DEFAULT 0 NOT NULL,
UNIQUE INDEX (id, date, cnt),
PRIMARY KEY (id)
);
To get your code working you have just to add the id into the insert query. For that your code will change a little bit to:
$date1 = date("Y-m-d");
$sql = "SELECT * FROM DateLog WHERE date='$date1'";
$result = $conn->query($sql);
$row = $result->fetch_assoc();
// Check if entry for the current date already exists
if (null === $row) {
// If not, set id to NULL
$id = 'NULL';
$dateindb = 1;
} else {
// If it exist, use it
$id = $row["id"];
$dateindb = $row["cnt"];
}
// Insert with id
$sql = "INSERT INTO DateLog (id, date, cnt) VALUES ($id,'$date1', '$dateindb') ON DUPLICATE KEY UPDATE cnt=cnt+1";
if (mysqli_query($conn, $sql)) {
} else {
echo mysqli_error($conn);
}
To simplify the situation, there is no need for an auto increment primary key, because you can use the date column as one. From this it follows that you also don’t need an unique index, too.
So simply change your Table definition to:
CREATE TABLE DateLog
(
date CHAR(10) PRIMARY KEY NOT NULL,
cnt INT DEFAULT 1
);
After you can use the this to count the uploads:
$date1 = date("Y-m-d");
$sql = "INSERT INTO DateLog (date) VALUES ('$date1') ON DUPLICATE KEY UPDATE cnt=cnt+1";
if (mysqli_query($conn, $sql)) {
} else {
echo mysqli_error($conn);
}
Simple, or not?
Hope this helps.

The error is pretty obvious... you are trying to insert duplicate values in a column, defined as unique...
cnt=cnt+21 gives you 2, which you already have in your table.

The problem is the field cnt_2, which is UNIQUE. That means it can't have the same value for two different registers. You aren't setting it a value in the INSERT query, so it takes the default value, which already exist in another register.

Related

How do I set my form number as M-0001, also a primary key in phpmyadmin? [duplicate]

I have table like this
table
id Varchar(45) NOT NULL AUTO_INCREMENT PRIMARY KEY,
name CHAR(30) NOT NULL,
I want to increment my id field like 'LHPL001','LHPL002','LHPL003'... etc.
What should I have to do for that? Please let me know any possible way.
If you really need this you can achieve your goal with help of separate table for sequencing (if you don't mind) and a trigger.
Tables
CREATE TABLE table1_seq
(
id INT NOT NULL AUTO_INCREMENT PRIMARY KEY
);
CREATE TABLE table1
(
id VARCHAR(7) NOT NULL PRIMARY KEY DEFAULT '0', name VARCHAR(30)
);
Now the trigger
DELIMITER $$
CREATE TRIGGER tg_table1_insert
BEFORE INSERT ON table1
FOR EACH ROW
BEGIN
INSERT INTO table1_seq VALUES (NULL);
SET NEW.id = CONCAT('LHPL', LPAD(LAST_INSERT_ID(), 3, '0'));
END$$
DELIMITER ;
Then you just insert rows to table1
INSERT INTO Table1 (name)
VALUES ('Jhon'), ('Mark');
And you'll have
| ID | NAME |
------------------
| LHPL001 | Jhon |
| LHPL002 | Mark |
Here is SQLFiddle demo
Create a table with a normal numeric auto_increment ID, but either define it with ZEROFILL, or use LPAD to add zeroes when selecting. Then CONCAT the values to get your intended behavior. Example #1:
create table so (
id int(3) unsigned zerofill not null auto_increment primary key,
name varchar(30) not null
);
insert into so set name = 'John';
insert into so set name = 'Mark';
select concat('LHPL', id) as id, name from so;
+---------+------+
| id | name |
+---------+------+
| LHPL001 | John |
| LHPL002 | Mark |
+---------+------+
Example #2:
create table so (
id int unsigned not null auto_increment primary key,
name varchar(30) not null
);
insert into so set name = 'John';
insert into so set name = 'Mark';
select concat('LHPL', LPAD(id, 3, 0)) as id, name from so;
+---------+------+
| id | name |
+---------+------+
| LHPL001 | John |
| LHPL002 | Mark |
+---------+------+
I know it is late but I just want to share on what I have done for this. I'm not allowed to add another table or trigger so I need to generate it in a single query upon insert. For your case, can you try this query.
CREATE TABLE YOURTABLE(
IDNUMBER VARCHAR(7) NOT NULL PRIMARY KEY,
ENAME VARCHAR(30) not null
);
Perform a select and use this select query and save to the parameter #IDNUMBER
(SELECT IFNULL
(CONCAT('LHPL',LPAD(
(SUBSTRING_INDEX
(MAX(`IDNUMBER`), 'LHPL',-1) + 1), 5, '0')), 'LHPL001')
AS 'IDNUMBER' FROM YOURTABLE ORDER BY `IDNUMBER` ASC)
And then Insert query will be :
INSERT INTO YOURTABLE(IDNUMBER, ENAME) VALUES
(#IDNUMBER, 'EMPLOYEE NAME');
The result will be the same as the other answer but the difference is, you will not need to create another table or trigger. I hope that I can help someone that have a same case as mine.
Here is PostgreSQL example without trigger if someone need it on PostgreSQL:
CREATE SEQUENCE messages_seq;
CREATE TABLE IF NOT EXISTS messages (
id CHAR(20) NOT NULL DEFAULT ('message_' || nextval('messages_seq')),
name CHAR(30) NOT NULL,
);
ALTER SEQUENCE messages_seq OWNED BY messages.id;

How to get all values from a database column

I have a basic system I am creating in which a user creates goals. When the goal is inserted, it is given a value of 0 to the status column. When the goal is completed, the value is updated to 1. So, what I am trying to do is fetch the specific user's (user with the current session) total number of ids (rows for the amount of goals) and then get the values of the status column and then count those. Once the actual status column values have been added, I want to divide that by the total number of id's. I am basically trying to figure out how to get a rate of completion.
I am not certain how I can:
-count the number of total id's for the user.
-get the values of the status column for the user and then add those.
Can anyone point me in the right direction?
Table
Create Table
goals
CREATE TABLE `goals` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`user_id` int(11) NOT NULL,
`title` text COLLATE utf8_unicode_ci NOT NULL,
`description` text COLLATE utf8_unicode_ci NOT NULL,
`status` int(5) NOT NULL,
`importance` int(5) NOT NULL,
`date` datetime NOT NULL,
PRIMARY KEY (`id`)
) ENGINE=MyISAM AUTO_INCREMENT=4 DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_c
$select_goals_sql = "
SELECT *
FROM goals
WHERE user_id = ?
ORDER BY id DESC
";
if ($select_goals_stmt = $con->prepare($select_goals_sql)) {
$select_goals_stmt->execute(array($user_id));
$rows = $select_goals_stmt->fetchAll(PDO::FETCH_ASSOC);
$goals = array();
foreach ($rows as $row) {
$goal_date = $row['date'];
$fixed_goal_date = fixDate($goal_date);
// the varialbe I will name it $status_completed =
$html = "";
Edit:
$goal_total_sql = "
SELECT sum(status) as sumna,
COUNT(*) as cnt
FROM goals
WHERE user_id = ?
";
if ($goal_total_stmt = $con->prepare($goal_total_sql)) {
$goal_total_stmt->execute(array($user_id));
$rows = $goal_total_stmt->fetchAll(PDO::FETCH_ASSOC);
foreach ($rows as $row) {
$actual_status = $row['status'];
$total_status = $row['id'];
}
}
?>
<div id="main">
<?php
echo "Actual:". $actual_status;
echo "Total". $total_status;
?>
SELECT status_id FROM goals WHERE userId = ? GROUP BY status_id should count the number of ids for each state
SELECT COUNT(*) as goal_count, status FROM goals WHERE user_id = ? GROUP BY status;
This will show you in tabular format the goal_count next to the status.
here is a sqlfiddle:
http://sqlfiddle.com/#!9/1bb23
so using a modified version of your create table (You should be using Innodb and I ommited the Collac for simplicity)
your result should be like this:
+------------+--------+
| goal_count | status |
+------------+--------+
| 1 | 1 |
| 2 | 2 |
| 2 | 3 |
| 2 | 4 |
+------------+--------+
I's hard to tell what you need here because the question title contradicts with body and both with code provided. But as far as I can tell
SELECT sum(status) as summa, COUNT(*) as cnt FROM ...

Mysql - On Duplicate Key Update not working for 2 keys

Hello I have a table with two unique keys profile_id and date. I don't know where is the problem but my query is not working.
Table:
CREATE TABLE `profile_views`
(\n `id` int(11) NOT NULL AUTO_INCREMENT,
\n `profile_id` varchar(45) DEFAULT NULL,
\n `counter` varchar(45) DEFAULT NULL,
\n `date` date DEFAULT NULL,
\n PRIMARY KEY (`id`),
\n UNIQUE KEY `date_UNIQUE` (`date`),
\n UNIQUE KEY `profile_id_UNIQUE` (`profile_id`)\n
) ENGINE=InnoDB AUTO_INCREMENT=150 DEFAULT CHARSET=latin1'
Data Right Now:
# id , profile_id, counter, date
113, 2 , 36 , 2015-08-27
I issue this command:
INSERT INTO profile_views (profile_id, counter, date)
VALUES (2, 1, '2015-08-28')
ON DUPLICATE KEY UPDATE counter = counter+1;
And
INSERT INTO profile_views (profile_id, counter, date)
VALUES (2, 1, '2015-08-27')
ON DUPLICATE KEY UPDATE counter = counter+1;
In this query i just changed the date so it should insert new row.
My Desired Results:
If i change date still it changing the same profile id counter.
I want to store everyday profile views for each profile id. So if the date and profile id is same its increment the counter otherwise insert new row.
Any help? Thanks.
Schema:
CREATE TABLE `profile_views`
(
`id` int(11) NOT NULL AUTO_INCREMENT,
`profile_id` varchar(45) DEFAULT NULL,
`counter` varchar(45) DEFAULT NULL,
`date` date DEFAULT NULL,
PRIMARY KEY (`id`),
UNIQUE KEY `date_UNIQUE` (`date`),
UNIQUE KEY `profile_id_UNIQUE` (`profile_id`)
) ENGINE=InnoDB auto_increment=150;
insert profile_views (id,profile_id,counter,date) values (113,2,36,'2015-08-27');
...
...
select * from profile_views;
+-----+------------+---------+------------+
| id | profile_id | counter | date |
+-----+------------+---------+------------+
| 113 | 2 | 36 | 2015-08-27 |
+-----+------------+---------+------------+
INSERT INTO profile_views (profile_id, counter, date)
VALUES (2, 1, '2015-08-28')
ON DUPLICATE KEY UPDATE counter = counter+1;
-- 2 row(s) affected
select * from profile_views;
+-----+------------+---------+------------+
| id | profile_id | counter | date |
+-----+------------+---------+------------+
| 113 | 2 | 37 | 2015-08-27 |
+-----+------------+---------+------------+
INSERT INTO profile_views (profile_id, counter, date)
VALUES (2, 1, '2015-08-27')
ON DUPLICATE KEY UPDATE counter = counter+1;
-- 2 row(s) affected
select * from profile_views;
+-----+------------+---------+------------+
| id | profile_id | counter | date |
+-----+------------+---------+------------+
| 113 | 2 | 38 | 2015-08-27 |
+-----+------------+---------+------------+
It looks good to me. Each insert on duplicate update has a unique key clash, allowing the update to happen. What clashes? Well the unique key on profile_id does.
What am I missing?
If you lay things out step by step, people can visualize it better :>
Edit: (OP changed his mind)
CREATE TABLE `profile_views`
(
`id` int(11) NOT NULL AUTO_INCREMENT,
`profile_id` varchar(45) DEFAULT NULL,
`counter` varchar(45) DEFAULT NULL,
`date` date DEFAULT NULL,
PRIMARY KEY (`id`),
UNIQUE KEY `combo_thingie1` (profile_id,`date`) -- unique composite
) ENGINE=InnoDB auto_increment=150;
insert profile_views (id,profile_id,counter,date) values (113,2,36,'2015-08-27');
... ...
select * from profile_views;
+-----+------------+---------+------------+
| id | profile_id | counter | date |
+-----+------------+---------+------------+
| 113 | 2 | 36 | 2015-08-27 |
+-----+------------+---------+------------+
INSERT INTO profile_views (profile_id, counter, date)
VALUES (2, 1, '2015-08-28')
ON DUPLICATE KEY UPDATE counter = counter+1;
select * from profile_views;
+-----+------------+---------+------------+
| id | profile_id | counter | date |
+-----+------------+---------+------------+
| 113 | 2 | 36 | 2015-08-27 |
| 150 | 2 | 1 | 2015-08-28 |
+-----+------------+---------+------------+
INSERT INTO profile_views (profile_id, counter, date)
VALUES (2, 1, '2015-08-27')
ON DUPLICATE KEY UPDATE counter = counter+1;
select * from profile_views;
+-----+------------+---------+------------+
| id | profile_id | counter | date |
+-----+------------+---------+------------+
| 113 | 2 | 37 | 2015-08-27 |
| 150 | 2 | 1 | 2015-08-28 |
+-----+------------+---------+------------+
I came up with this mad structure - it inserts new records for new dates and then updates on successive insert statements - thus incrementing the counter.
CREATE TABLE `profile_views` (
`id` INT(11) NOT NULL AUTO_INCREMENT,
`profile_id` VARCHAR(45) NOT NULL,
`counter` VARCHAR(45) NOT NULL,
`date` DATE NOT NULL,
PRIMARY KEY (`id`, `profile_id`, `date`),
UNIQUE INDEX `profile_id_date` (`profile_id`, `date`),
UNIQUE INDEX `id_profile_id_date` (`id`, `profile_id`, `date`)
)
COLLATE='latin1_swedish_ci'
ENGINE=InnoDB
AUTO_INCREMENT=267;

"Integrity constraint violation: 1062 Duplicate entry" - but no duplicate rows

I'm converting an app from native mysqli calls to PDO. Running into an error when attempting to insert a row into a table with a foreign key constraint.
Note: this is a simplified test case and should not be copy/pasted into a production environment.
Info PHP 5.3, MySQL 5.4
First, here are the tables:
CREATE TABLE `z_one` (
`customer_id` int(10) unsigned NOT NULL DEFAULT '0',
`name_last` varchar(255) DEFAULT NULL,
`name_first` varchar(255) DEFAULT NULL,
`dateadded` datetime DEFAULT NULL,
PRIMARY KEY (`customer_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
INSERT INTO `z_one` VALUES (1,'Khan','Ghengis','2014-12-17 10:43:01');
CREATE TABLE `z_many` (
`order_id` varchar(15) NOT NULL DEFAULT '',
`customer_id` int(10) unsigned DEFAULT NULL,
`dateadded` datetime DEFAULT NULL,
PRIMARY KEY (`order_id`),
KEY `order_index` (`customer_id`,`order_id`),
CONSTRAINT `z_many_ibfk_1` FOREIGN KEY (`customer_id`) REFERENCES `z_one` (`customer_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
Or if you prefer,
mysql> describe z_one;
+-------------+------------------+------+-----+---------+-------+
| Field | Type | Null | Key | Default | Extra |
+-------------+------------------+------+-----+---------+-------+
| customer_id | int(10) unsigned | NO | PRI | 0 | |
| name_last | varchar(255) | YES | | NULL | |
| name_first | varchar(255) | YES | | NULL | |
| dateadded | datetime | YES | | NULL | |
+-------------+------------------+------+-----+---------+-------+
4 rows in set (0.00 sec)
mysql> describe z_many;
+-------------+------------------+------+-----+---------+-------+
| Field | Type | Null | Key | Default | Extra |
+-------------+------------------+------+-----+---------+-------+
| order_id | varchar(15) | NO | PRI | | |
| customer_id | int(10) unsigned | YES | MUL | NULL | |
| dateadded | datetime | YES | | NULL | |
+-------------+------------------+------+-----+---------+-------+
3 rows in set (0.00 sec)
Next, here is the query:
$order_id = '22BD24';
$customer_id = 1;
try
{
$q = "
INSERT INTO
z_many
(
order_id,
customer_id,
dateadded
)
VALUES
(
:order_id,
:customer_id,
NOW()
)
";
$stmt = $dbx_pdo->prepare($q);
$stmt->bindValue(':order_id', $order_id, PDO::PARAM_STR);
$stmt->bindValue(':customer_id', $customer_id, PDO::PARAM_INT);
$stmt->execute();
} catch(PDOException $err) {
// test case only. do not echo sql errors to end users.
echo $err->getMessage();
}
This results in the following PDO error:
SQLSTATE[23000]: Integrity constraint violation: 1062 Duplicate entry
'22BD24' for key 'PRIMARY'
The same query works fine when handled by mysqli. Why is PDO rejecting the INSERT with a 'duplicate entry' message when there aren't any duplicates found?
Since not all code is available (from php side) just in case your query is in some sort of loop the quickest (and perhaps partly) solution to this is the following:
$order_id = '22BD24';
$customer_id = 1;
try {
$q = "INSERT INTO `z_many` (`order_id`,`customer_id`,`dateadded`)
VALUES (:order_id,:customer_id,NOW())
ON DUPLICATE KEY UPDATE `dateadded`=NOW()";
$stmt = $dbx_pdo->prepare($q);
$stmt->bindValue(':order_id', $order_id, PDO::PARAM_STR);
$stmt->bindValue(':customer_id', $customer_id, PDO::PARAM_INT);
$stmt->execute();
} catch(PDOException $err) {
// test case only. do not echo sql errors to end users.
echo $err->getMessage();
}
I've copied the SQL schema you provided on my mysql DB and added script code, but with PDO initialization at the start:
$dbx_pdo = new PDO('mysql:host=127.0.0.1;dbname=test12;charset=utf8','root','');
.. and it worked fine, but my setup is php 5.5.9 and mysql 5.6.16
So I think your code executes twice and maybe its inside of a transaction, so you get rollback. Need to know more context
Please REMOVE default for primary key column. Also use the construction
INSERT INTO (`field1`, `field2`, `...`) values (val1, val2, val3);
If you tell what default value is for inserts - some mysql versions can see errors when inserting. Thats why you should use auto-increment or dont use default value at all.
Just a shot in the dark. I use PDO with ORACLE PL/SQL only with bindParam(). And have a look at the forth parameter ,15 if it is a PARAM_STR value. So try this, hope it helps.
$stmt->bindParam(':order_id', $order_id, PDO::PARAM_STR, 15);
$stmt->bindParam(':customer_id', $customer_id, PDO::PARAM_INT);
This 15 descibes the (bufffer-)length from order_id in your table.

How do I make a SQL Command with INSERT AND COUNT

I don't know how to COUNT a column named id. I tried
mysql_query("INSERT INTO `servers` (`user_id`, `ip`, `port`, `banner`, `disabled`, `vip`,`premium`, `name`, `status`, `votifier_key`, `votifier_port`, `country`)
VALUES ('$session_user_id', '$ip', '$port', 's=.'id'.back', '$disabled', 0,'false', '$name', '1', '$votifier', '$votPort', '$country')");
But it's not working, because I couldn't get id. Can someone help?
You need to use INSERT ... SELECT request.
Suppose, we have an empty table test:
test
|----+-------|
| id | value |
|----+-------|
CREATE TABLE IF NOT EXISTS `test` (
`id` int(10) unsigned NOT NULL AUTO_INCREMENT,
`value` int(10) unsigned DEFAULT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
When we run this SQL request:
INSERT INTO test (value) SELECT COUNT(*) FROM `test`
we shall sequentially get test filling up with data:
| id | value |
|----+-------|
| 1 | 0 |
| 2 | 1 |
| 3 | 2 |
Use this approach for your table, and you'll get what you need.

Categories