INSERT INTO or UPDATE with two conditions - mysql

This problem seems easy at first sight, but I simply have not found a solution that is reasonable time wise.
Consider a table with the following characteristics:
ID INTEGER PRIMARY KEY AUTOINCREMENT
name INTEGER
values1 INTEGER
values2 INTEGER
dates DATE
Every day, N amount of new rows are generated, for dates into the future, and with the 'name' coming from a finite list. I would like to insert a new row when there is new data, but if there is already a row with 'name' and 'dates', simply update it.
Please note that a current proposed solution of an SPROC that checks the conditional is not feasible, as this is data being pushed from another language.

that is what insert on duplicate key update is for.
The Manual page for it is here.
The trick is that the table needs to have a unique key (can be a composite) so that the clash of doing an insert can be detected. As such, the update to occur on that row, otherwise an insert. It can be a primary key, of course.
In your case, you could have a composite key such as
unique key(theName,theDate)
If the row is already there, the clash is detected, and the update happens.
Here is a complete example
create table myThing
( id int auto_increment primary key,
name int not null,
values1 int not null,
values2 int not null,
dates date not null,
unique key(name,dates) -- <---- this line here is darn important
);
insert myThing(name,values1,values2,dates) values (777,1,1,'2015-07-11') on duplicate key update values2=values2+1;
insert myThing(name,values1,values2,dates) values (778,1,1,'2015-07-11') on duplicate key update values2=values2+1;
-- do the 1st one a few more times:
insert myThing(name,values1,values2,dates) values (777,1,1,'2015-07-11') on duplicate key update values2=values2+1;
insert myThing(name,values1,values2,dates) values (777,1,1,'2015-07-11') on duplicate key update values2=values2+1;
insert myThing(name,values1,values2,dates) values (777,1,1,'2015-07-11') on duplicate key update values2=values2+1;
show results
select * from myThing;
+----+------+---------+---------+------------+
| id | name | values1 | values2 | dates |
+----+------+---------+---------+------------+
| 1 | 777 | 1 | 4 | 2015-07-11 |
| 2 | 778 | 1 | 1 | 2015-07-11 |
+----+------+---------+---------+------------+
As expected, insert on duplicate key update works, just 2 rows.

This is easy:
Create a unique key on the columns to check
Use the INSERT .. ON DUPLICATE KEY UPDATE construct

Related

Bi-directional unique key constraint for combination of two columns

I have the below table columns in MySQL.
id
user_primary_email
user_secondary_email
I want to make the combination of columns user_primary_email and user_secondary_email unique which I can achieve by using UNIQUE KEY unique_key_name (user_primary_email, user_secondary_email)
The above addition of unique key constraint will help me achieve the below scenario or rather just by adding a unique key to the individual column itself.
user_primary_email = 'xyz#gmail.com' AND user_secondary_email = 'pqr#gmail.com'
user_primary_email = 'xyz#gmail.com' AND user_secondary_email = 'pqr#gmail.com' //This will not be allowed to enter due to unique key constraint
Now the problem which I am facing is the same combination should not be allowed to add in a reverse way as mentioned below.
user_primary_email = 'pqr#gmail.com' AND user_secondary_email = 'xyz#gmail.com' //This should not be allowed to add since already same email id combination added once
id | user_primary_email | user_secondary_email
-------------------------------------------------------
1 | xyz#gmail.com | pqr#gmail.com
-------------------------------------------------------
2 | pqr#gmail.com | xyz#gmail.com
-------------------------------------------------------
In the above case during insert of row id 2 it should throw error as both the email id combination is already used in row id 1.
Any help would be great.
In any MariaDB:
CREATE TABLE `t` (
`id` int(11) NOT NULL,
`user_primary_email` varchar(64) DEFAULT NULL,
`user_secondary_email` varchar(64) DEFAULT NULL,
`mycheck` varchar(128) AS (IF(user_primary_email<user_secondary_email,CONCAT(user_primary_email,user_secondary_email),CONCAT(user_secondary_email,user_primary_email))) PERSISTENT,
PRIMARY KEY (`id`),
UNIQUE KEY `mycheck` (`mycheck`)
);
MariaDB [test]> insert into t values (1,'a','b',null);
Query OK, 1 row affected (0.03 sec)
MariaDB [test]> insert into t values (2,'b','a',null);
ERROR 1062 (23000): Duplicate entry 'ab' for key 'mycheck'
There is no direct support for that, but you can use a workaround to create your bidirectional key: You need a unique key on an ordered version of your two columns.
Fortunately, you can very easily do that. MySQL 5.7.6+ supports generated columns and unique indexes for them, which you can use to order your two values and to enforce uniqueness.
create table testBiDirKey (
a varchar(100),
b varchar(100),
a_ordered varchar(100) as (least(a, b)) STORED,
b_ordered varchar(100) as (greatest(a, b)) STORED,
unique key unqBi_test_ab (a_ordered, b_ordered)
);
insert into testBiDirKey(a,b) values('a', 'b');
insert into testBiDirKey(a,b) values('b', 'a');
Error Code: 1062. Duplicate entry 'a-b' for key 'unqBi_test_ab'
This will treat null exactly as your current normal unique key, so
insert into testBiDirKey(a,b) values('a', null);
insert into testBiDirKey(a,b) values('a', null);
insert into testBiDirKey(a,b) values(null, 'a');
are all allowed. You can add coalesce(x,'') to only allow one empty value (either null OR '') if you want. If you verify your values before you add them (e.g. if they don't contain a ,), you can combine the two columns to just one, concatenated with an , - although with little benefit apart from just having 1 additional column.
For 5.7.8+, you don't need the STORED keyword anymore to be able to use these columns in an index. That keyword effects if the values are stored (using disk space) or calculated when required (default).
Before MySQL 5.7.6, you can use a trigger (on update and insert) to update the two columns with the these values, the same logic applies, it's just a little more code.

ERROR 1062 (23000): Duplicate entry '2147483647' for key 'PRIMARY'

I have a table:
CREATE TABLE passenger_details
(
bank_card INT(20) NOT NULL AUTO_INCREMENT,
email VARCHAR(20),
mobile INT(15) NOT NULL,
p_id INT NOT NULL,
PRIMARY KEY (bank_card),
FOREIGN KEY (p_id) REFERENCES passenger(p_id)
);
INSERT INTO passenger_details
VALUES (0123012301230123,'blah_#hotmail.com',0872863492,1234);
select*from passenger_details;
+------------+--------------------+-----------+------+
| bank_card | email | mobile | p_id |
+------------+--------------------+-----------+------+
| 2147483647 | blah_#hotmail.com | 872863492 | 1234 |
+------------+--------------------+-----------+------+
1 row in set (0.00 sec)
As we can see, the previous value, just went wrong into table. Should be 16 numbers and not only 10, actually different numbers.
When i try to insert a new value:
INSERT INTO passenger_details
VALUES (1234258431681842,'blah#icloud.com',0895764829,123548);
I get this error:
ERROR 1062 (23000): Duplicate entry '2147483647' for key 'PRIMARY'
If bank_card is AUTO_INCREMENT why there is error? Should I change the PK to another place?
INT has a maximum signed value of 2147483647. Any number greater than that will be truncated to that value. What you need to do is change that column to be a varchar(20) which will hold strings of up to 20 characters since bank card numbers are strings and not actually numbers (you don't do math with the). You also should remove AUTO_INCREMENT as that is not a value you will be incrementing.
Something to ask yourself. How did the number get that big? I did not insert 2 billion rows!
Well, possibly you 'burned' that many AUTO_INCREMENT ids. This can happen in man ways:
INSERT IGNORE ... -- when the insert is ignored (because it the row already exists)
REPLACE
IODKU
and probably others.
With MySQL phpmyadmin panel , this is how I got rid from this issue
>Go to your Table's structure from phpmyadmin panel
>> select that PRIMARY column , click on change
>>> Change Column type to "BIGINT" and Attributes to "unsigned"
with other SQLs > change column attributes to "BIGINT unsigned"
that worked for me

insert into table with no value

I have a table which only has two column:
+------------------+-------------+----------------------------+
| user_id | INT | AUTO_INCREMENT |
+------------------+-------------+----------------------------+
| user_timestamp | TIMESTAMP | DEFAULT CURRENT_TIMESTAMP |
+------------------+-------------+----------------------------+
Now I am quite confused how will I build my INSERT since all the values has default. I have this but seems not working $query = "INSERT INTO tt_users (user_id) VALUES ()";. I just want MySQL to insert a new user_id which I will retrieve using lastInsertID. Pardon, this is my first time doing this.
INSERT INTO tt_users (user_id) VALUES (null)
you can not insert the user_id.. that one is generated automatically. that's why you have AUTO_INCREMENT .. you can only insert timestamp, and even that is optional since you do have a default value assigned...

Remove duplicates records in a MySQL table with key but not primary key

I need to remove duplicate records (just to keep one copy) from a MySQL table in MyISAM format. I have read many questions in Stackoverflow about similar issues but always the people use an ID field as unique id or similar and I haven't this field because my "Key" could be duplicated. I want to remove rows with the 'Fecha' and 'Equip' duplicated.
CREATE TABLE `pfc` (
`Fecha` datetime NOT NULL,
`Equip` int(10) unsigned NOT NULL,
`Value` double NOT NULL,
KEY `Fecha` (`Fecha`)
) ENGINE=MyISAM DEFAULT CHARSET=latin1 AVG_ROW_LENGTH=21 ROW_FORMAT=FIXED;
An example table data:
Fecha | Equip | Value
06/02/2011 0:00:11 | 22 | 29.0
06/02/2011 0:22:11 | 22 | 45.3
06/02/2011 0:00:11 | 22 | 29.0
The result should be:
Fecha | Equip | Value
06/02/2011 0:00:11 | 22 | 29.0
06/02/2011 0:22:11 | 22 | 45.3
This structure is not possible to change. I cannot use PRIMARY KEY or UNIQUE INDEX solutions. To create a temporal table without duplicates and then rename would be a poor solutions also, because the KEY and another parameters will be lost.
Thanks
ALTER IGNORE TABLE `pfc` ADD UNIQUE(`Fetcha`, `Equip`);
That will keep the first record it finds and remove duplicates from your table.
From MySQL manual:
IGNORE is a MySQL extension to standard SQL. It controls how ALTER
TABLE works if there are duplicates on unique keys in the new table or
if warnings occur when strict mode is enabled. If IGNORE is not
specified, the copy is aborted and rolled back if duplicate-key errors
occur. If IGNORE is specified, only the first row is used of rows with
duplicates on a unique key. The other conflicting rows are deleted.
Incorrect values are truncated to the closest matching acceptable
value.
Edit:
To create an exact copy of your table, use the following:
CREATE TABLE table_copy SELECT * FROM pfc;
That will copy the table structure and the data. After that, run the ALTER command to add the UNIQUE constraint and filter out the records that are duplicated.
Just as a test, try this to see if it is what you want
CREATE TABLE new_pfc AS
SELECT * FROM pfc GROUP BY fecha, equip
DELETE n1 FROM pfc n1, pfc n2 WHERE n1.Fecha = n2.Fecha AND n1.Equip=n2.Equip AND n1.Value=n2.Value

Mysql -- inserting in table with only an auto incrementing column

Lets say we have table A with just one column, id(which is the primary key)
How do we insert a new row into the table without specifying an id?
I tried this
INSERT INTO A (`id`) VALUES (NULL)
and it doesn't work
Edit: I forgot to mention that id, the primary key has the auto_increment and NOT NULL attribute.
Edit 2: The exact error when running the query above is
Column 'id' cannot be null
As soon as 'id' as the auto-increment enable (assuming ID is an integer), you can just do:
INSERT INTO A (id) values (null)
and 'id' will keep incrementing each time.
only works if you're using an auto_increment primary key (PK) as every PK must have a unique, non null value.
drop table if exists A;
create table A
(
id int unsigned not null auto_increment primary key
)
engine=innodb;
insert into A (id) values (null),(null);
mysql> select * from A order by id;
+----+
| id |
+----+
| 1 |
| 2 |
+----+
2 rows in set (0.00 sec)
I had a similar issue, then I noticed that I didn't apply the changes when I changed id to primary key + not null + auto incremental.
INSERT INTO `table` () VALUES ();
is working too.
Try it without the ``..
As in:
INSERT INTO A(sid) VALUES(NULL); //i used sid instead of id...
worked fine for me..
Also wwhile creating the table A, specify unique(sid)...
i.e
create table A(sid int(3) not null auto_increment unique(sid));