Why isn't the primary key incrementing ON DUPLICATE? - mysql

I have the following TEACHER table that has the following schema:
create table TEACHER
(
TEACHERID int not null auto_increment,
FIRST_NAME varchar(20) not null,
SURNAME varchar(20) not null,
primary key (TEACHERID)
);
I have multiple inserts with the same first name and surname of teacher that I wish to omit. The schema is given and I don't plan on modifying it.
I try to execute dynamically in my program the following query but the TEACHERID is not incrementing, actually no new fields with new first name and last name are added, there is only one field that is constantly being updated.
Here is my query:
INSERT INTO TEACHER set ? ON DUPLICATE KEY UPDATE FirstName = ?, LastName = ?'
with the ? are defined as follows: values: [set, professor.name, professor.sname ]
where a set is defined as follows:
set = {
FirstName: professor.name,
LastName: professor.sname
}
How do I get the primary key to increment on each duplicate, without actually adding that duplicate?
Thank you

You are getting that behavior cause you are using ON DUPLICATE KEY UPDATE. If you really want to insert the duplicate record then just perform a INSERT statement like
INSERT INTO TEACHER VALUES('test','test')
How do I get the primary key to increment on each duplicate, without
actually adding that duplicate?
Sorry that's not possible at-least with auto increment. You will then have to have your own primary key and on every insert do some manipulation through a before insert trigger. Something like
create table TEACHER
(
TEACHERID int not null primary key,
create trigger trg_binsert
on TEACHER before insert
for each row
begin
if(new.FIRST_NAME = FIRST_NAME and new.SURNAME = SURNAME)
update TEACHER
SET TEACHERID = TEACHERID + 1
WHERE new.FIRST_NAME = FIRST_NAME
and new.SURNAME = SURNAME;
end if
end
Though, not sure why you want to do that and won't recommend as well.

Related

2 problems when trying to create a trigger in MySQL

I am trying to understand triggers in MySQL, but am having a few problems.
I'm trying to implement a trigger which on every UPDATE/INSERT in the table Grades it updates the column "gpa" in another table called Student, but cannot do it properly.
Code:
CREATE TABLE Student
(
Id INT NOT NULL AUTO_INCREMENT PRIMARY KEY,
name VARCHAR(30),
age TINYINT,
gpa NUMERIC(3, 2) DEFAULT 2
);
CREATE TABLE Grades
(
StudentId INT PRIMARY KEY,
grade_bg INT,
grade_math INT,
grade_subd INT,
FOREIGN KEY(StudentId) references Student(Id)
);
delimiter |
CREATE TRIGGER update_gpa
AFTER INSERT
ON Grades
FOR EACH ROW
BEGIN
UPDATE Student SET gpa = ((grade_bg + grade_math + grade_subd)/3) WHERE StudentId = Id;
END;
|
After this when I try to insert in the table Student I get:
"Error 1054: Unknown column 'StudentId' in where clause".
For example:
INSERT INTO Student(name, age)
VALUES ('Joshua', 17);
Also when I try writing "AFTER INSERT, UPDATE" I get a syntax error from the MySQL Workbench and don't know how to make the trigger activate on INSERT AND UPDATE in the table Grades.
Any help is appreciated! Thanks in advance!
I don't know much about Triggers but I tried just running the update statement and noticed you hadn't defined the join:-
UPDATE Student
INNER JOIN Grades ON Grades.StudentId = Student.Id
SET Student.gpa = ((Grades.grade_bg + Grades.grade_math + Grades.grade_subd)/3);

Mysql How do I insert multiple table with duplicate key checking?

I hope to this work.
When UserAccount table duplicated, Out Parameter put -1.
When UserInfo table duplicated, Out Parameter put -2.
When all work is succeed, Out Parameter put LAST_INSERT_ID.
UserAccount Table
CREATE TABLE UserAccount (
SocialType ENUM('Google', 'Facebook'),
SocialID BINARY(16),
UserID INT UNIQUE NOT NULL AUTO_INCREMENT,
PRIMARY KEY(SocialType, SocialID)
);
UserInfo Table
CREATE TABLE UserInfo (
UserID INT,
Nickname VARCHAR(20) UNIQUE,
PRIMARY KEY(UserID),
FOREIGN KEY(UserID) REFERENCES UserAccount(UserID)
ON DELETE CASCADE,
);
I want to insert tables with duplicate checking in procedure.
But it failed to work and seems inefficient.
DELIMITER $$
CREATE PROCEDURE usp_CreateNewUser(
socialType ENUM('Google','Facebook'),
socialID VARCHAR(100),
nickname VARCHAR(20),
OUT result INT)
Work:BEGIN
IF EXISTS(SELECT 1 FROM UserAccount WHERE SocialType = socialType AND SocialID = UNHEX(MD5(socialID)))
THEN
SET result = -1;
Leave Work;
END IF;
IF EXISTS(SELECT 1 FROM UserInfo WHERE Nickname = nickname)
THEN
SET result = -2;
Leave Work;
END IF;
INSERT INTO UserAccount() VALUE(socialType, UNHEX(MD5(socialID)), 0);
INSERT INTO UserInfo(UserID, Nickname) VALUE(LAST_INSERT_ID(), nickname);
SET result = LAST_INSERT_ID();
END $$
DELIMITER ;
What is the best way I can do in this situation?
Thanks.
Judging from your trigger, you don't want to have duplicate keys in your database, as you are bypassing the insert when you find one.
So all you have to do is have your unique indexes set up correctly in your first table, which will do that work for you, and produce a display in your application.
Do the below:
ALTER TABLE `UserAccount` ADD UNIQUE `UserAccount`(`socialType`, `socialID`);
Since your data appears to be 1 to 1, id put all of this in the same table, and then you wouldn't need the trigger.

Recover indexes primary key

which middle safer for mes to recover and Sort indexes primary key, avoiding unnecessary update throughout the database? Can you show me any examples?
I just wanna that primary keys were constant and dynamic.I just wanna that primary keys were constraint and dinamic
ps: MySQL Database
User's Table
|| user_id || user_first_name || user_last_name
#1 Alexandre Doria
#2 Ilya Bursov
#3 Anybody Anybody
So, if i DELETE the #2 row, and INSERT a new row, the primary key of #3 row is duplicated.
My PHP code here:
$user_id_cont = mysql_query("select 'user_id' from user");
$user_id = mysql_num_rows($user_id_cont)+1;
It absolutely wrong to calculate primary keys as it done in your code
First of all - change user_id column to be primary key (it will be unique too then), also set it to be auto_increment, so your table create statement must be:
create table sample_users (
`user_id` int unsigned not null auto_increment,
`first` varchar(255),
`last` varchar(255),
primary key (`user_id`)
);
next, you need to insert data into your table, so you can just insert it:
INSERT into `sample_users` (`first`, `last`) values('fname', 'lname');
INSERT into `sample_users` (`first`, `last`) values('fname2', 'lname2');
...
mysql will generate appropriate user_id for each row, and even if you delete some of them - mysql still will provide you with unique values
additional case is - if you need to know what id is generated by mysql, you can use PHP mysql_insert_id or MySQL LAST_INSERT_ID functions for that
just for notice: wrong method, but it will work for "school project", change your code to:
$user_id_cont = mysql_query("select max('user_id') from user");
$user_id = mysql_fetch_array($user_id_cont, MYSQL_NUM);
$user_id = $user_id[0]+1;

how to pass a null value to a foreign key field?

I have 2 tables:
university:
university_id(p.k) | university_name
and user:
uid | name | university_id(f.k)
How to keep university_id NULL in user table?
I am writting only 1 query, my query is:
INSERT INTO user (name, university_id) VALUES ($name, $university_id);
Here $university_id can be null from front end.
university table will be set bydefault by me.
In the front end, student will select the university name, according to that the university_id will pass to user table, but if student is not selecting any university name then is should pass null value to the user table for university_id field.
Just allow column university_id of table user to allow NULL value so you can save nulls.
CREATE TABLE user
(
uid INT NOT NULL,
Name VARCHAR(30) NOT NULL,
university_ID INT NULL, -- <<== this will allow field to accept NULL
CONSTRAINT user_fk FOREIGN KEY (university_ID)
REFERENCES university(university_ID)
)
UPDATE 1
based on your comment, you should be inserting NULL and not ''.
insert into user (name,university_id) values ('harjeet', NULL)
UPDATE 2
$university_id = !empty($university_id) ? "'$university_id'" : "NULL";
insert into user (name,university_id) values ('harjeet', $university_id);
As a sidenote, the query is vulnerable with SQL Injection if the value(s) of the variables came from the outside. Please take a look at the article below to learn how to prevent from it. By using PreparedStatements you can get rid of using single quotes around values.
How to prevent SQL injection in PHP?
Here suppose i have foreign key user_id and i want to insert null value for that.
Checkbox must be checked for insert null value for foreign key.
I was using MySQL InnoDB and even allowing NULL in the FK column and using NULL as default I was getting an error.
So I used the SET syntax:
INSERT INTO (table) SET value1=X...
And I just don't set the FK column.

mySQL - Copy rows from one database to another with auto increment ids

Note: Apologies if this is a duplicate but I can't find a solution.
I have two databases (one dev and one live) which have exactly the same schema.
To make things easier to explain, assume I have a 'customer' table and a 'quote' table. Both tables have auto increment ids and the quote table has a 'customerid' column that serves as a foreign key to the customer table.
My problem is that I have some rows in my dev database that I want to copy to the live database. When I copy the customer rows I can easily get a new id, but how can i get the new id to be assigned to the 'child' quote table rows?
I know I can manually script out INSERTS to overcome the problem but is there an easier way to do this?
EDIT:
This is a simplified example, I have about 15 tables all of which form a hierarchy using auto-increments and foreign keys. There is considerably more data in the live database so the new ids will be bigger (e.g. dev.customer.id = 4, live.customer.id = 54)
Easiest way without changing any IDs.
Ensure that you are currently in the table where the record you want to copy is in (source db).
Run the following command:
INSERT INTO to_database.to_table
SELECT * FROM from_table WHERE some_id = 123;
No need to specify columns if there is no need to remap anything.
Hope that helps!
I eventually managed to do this (as per my comment) but in order to do so I had to write some code. In the end I created some dummy tables that kept track of the old id against new id so. When copying over records with FK constraints I just looked up the new id based on the old. A bit long winded but it worked.
This post is getting on a bit now so I've marked this as the answer. If anyone out there has better ideas/solutions that work I'll happily 'unmark' it as the accepted answer.
EDIT: As requested here is some pseudo-code that I hope explains how I did it.
I have the two related tables as follows:
CREATE TABLE tblCustomers (
Id int NOT NULL AUTO_INCREMENT,
Name varchar(50) DEFAULT NULL,
Address varchar(255) DEFAULT NULL,
PRIMARY KEY (Id)
)
ENGINE = MYISAM
ROW_FORMAT = fixed;
CREATE TABLE tblQuotes (
Id int NOT NULL AUTO_INCREMENT,
CustomerId int(11) DEFAULT NULL,
QuoteReference varchar(50) DEFAULT NULL,
PRIMARY KEY (Id)
)
ENGINE = MYISAM
ROW_FORMAT = fixed;
I create an extra table that I will use to track old ids against new ids
CREATE TABLE tblLookupId (
Id int NOT NULL AUTO_INCREMENT,
TableName varchar(50) DEFAULT NULL,
OldId int DEFAULT NULL,
NewId int DEFAULT NULL,
PRIMARY KEY (Id)
)
ENGINE = MYISAM
ROW_FORMAT = fixed;
The idea is that I copy the tblCustomer rows one at a time and track the ids as I go, like this:
// copy each customer row from dev to live and track each old and new id
//
foreach (customer in tblCustomers)
{
// track the old id
var oldid = customer.id; // e.g. 1
// insert the new record into the target database
INSERT newdb.tblCustomers (...) VALUES (...);
// get the new id
var newid = SELECT LAST_INSERT_ID() // e.g. 245
// insert the old id and the new id in the id lookup table
INSERT idlookup (TableName, OldId, NewId) VALUES ('tblCustomers', oldid, newid); // this maps 1->245 for tblCustomers
}
When I come to copy the table (tblQuote) with the foreign key I have to first lookup the new id based on the old.
// copy each quote row from dev to live and lookup the foreign key (customer) from the lookup table
//
foreach(quote in tblQuotes)
{
// get the old foreign key value
var oldcustomerid = quote.CustomerId; // e.g 1
// lookup the new value
var newcustomerid = SELECT newid FROM tblIdLookup WHERE TableName='tblCustomers' AND oldid=oldcustomerid; // returns 245
// insert the quote record
INSERT tblQuotes (CustomerId, ...) VALUES (newcustomerid, ...);
}
I've tried to keep this short and to the point (and language agnostic) so the technique can be seen. In my real scenario I had around 15 'cascading' tables so I had to track the new ids of every table not just tblCustomer
Use INSERT ... SELECT:
insert into your_table (c1, c2, ...)
select c1, c2, ...
from your_table
where c1, c2, ... are all the columns except id.