Foreign key violation error on row insert [duplicate] - java

This question already has answers here:
Mysql error 1452 - Cannot add or update a child row: a foreign key constraint fails
(21 answers)
Closed 8 years ago.
While a am trying to insert values to following table via jdbc i am getting error
Database schema
CREATE TABLE student_contact_details_t(
student_contact_details_id MEDIUMINT NOT NULL AUTO_INCREMENT,
student_id MEDIUMINT NOT NULL ,
contact_relation_type_id MEDIUMINT NOT NULL,
name varchar(255),
addresss varchar(255),
phone_no varchar(255),
created_by varchar(255),
created_date DATE,
modified_by varchar(255),
modified_date DATE,
PRIMARY KEY(student_contact_details_id),
FOREIGN KEY(student_id) REFERENCES student_details_t(student_id),
FOREIGN KEY(contact_relation_type_id) REFERENCES contact_relation_type_t(contact_relation_type_id)
);
Code
public void saveStudentContactDetails(
StudentContactDetailsTO studentContactDetails)
throws ClassNotFoundException, SQLException, IOException {
try {
int autoId = 0;
String Insertquery = "insert into student_contact_details_t(student_id,contact_relation_type_id,name,addresss,phone_no,created_by,created_date,modified_by,modified_date)values(?,?,?,?,?,?,?,?,?)";
PreparedStatement prepareStatement = JDBCConnectionUtil
.getConnection().prepareStatement(Insertquery,
Statement.RETURN_GENERATED_KEYS);
ResultSet studentId = prepareStatement.getGeneratedKeys();
prepareStatement.setInt(1, studentContactDetails.getStudentId());
// prepareStatement.setInt(2,studentId.getInt(1));
prepareStatement.setInt(2, autoId);
prepareStatement.setString(3, studentContactDetails.getName());
prepareStatement.setString(4, studentContactDetails.getAddress());
prepareStatement.setString(5, studentContactDetails.getPhoneNo());
prepareStatement.setString(6, "sysadmin");
prepareStatement.setString(7, DateUtil.getDate().format(date));
prepareStatement.setString(8, "sysadmin");
prepareStatement.setString(9, DateUtil.getDate().format(date));
prepareStatement.executeUpdate();
while (studentId.next()) {
autoId = studentId.getInt(1);
System.out.println(autoId);
}
} catch (ClassNotFoundException | SQLException | IOException e) {
throw e;
}
}
Exception
com.mysql.jdbc.exceptions.jdbc4.MySQLIntegrityConstraintViolationException: Cannot add or update a child row: a foreign key constraint fails (`studentregistration`.`student_contact_details_t`, CONSTRAINT `student_contact_details_t_ibfk_1` FOREIGN KEY (`student_id`) REFERENCES `student_details_t` (`student_id`))
at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method)
at sun.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:62)
at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:45)
at java.lang.reflect.Constructor.newInstance(Constructor.java:408)
at com.mysql.jdbc.Util.handleNewInstance(Util.java:377)
at com.mysql.jdbc.Util.getInstance(Util.java:360)

The error says that you are inserting student_id in table student_contact_details_t that does not exist in student_details_t table voilating the foreign key constraint that you set up during student_contact_details_t table creation.
So you have to first insert in table student_details_t then insert in student_contact_details_t with student_id

You have to validate that the student id exist in the student table student_details_t.
If the student doesn't exist in student_details_t then you can't insert in the related table student_contact_details_t.
In this scenario you should tell the user that "student XXX doesn't exist".

Related

Why a SQL SELECT statement doesn't return COUNT() result on Java Spring boot project?

this is my first question here so, please ask if you need more information. I am working on a personal project. I have a relatively complex relational database structure. I create schema.sql on my spring boot project as well as data.sql with sample data. I try to create a web application for simulated fitness centre web pages. I try to display the location name and number of visits for the user. I create a userLocation bean for keeping the result set as a list of the select query. I can test the statement on H2 database and its work. However, on my code, I cannot get the number of visits from the select statement.
Here is my userlocation bean,
#Data
#NoArgsConstructor
public class UserLocation {
private String locName;
private int numOfVisit;
}
Controller class getMapping method
#GetMapping("/secure/userLocation")
public String myLocation(Model model, Authentication authentication) {
String email = authentication.getName();
User currentUser = da.findUserAccount(email);
model.addAttribute("myLocationList", da.getUserLocationList(currentUser.getUserId()));
return "/secure/userLocation";
}
Here database access method;
public List<UserLocation> getUserLocationList(Long userId) {
MapSqlParameterSource namedParameters = new MapSqlParameterSource();
String query = "SELECT l.locName, COUNT(ul.dayOfVisit) FROM location l "
+ "INNER JOIN userLocation ul ON l.locId = ul.locId "
+ "INNER JOIN sec_user sc ON ul.userId = sc.userId "
+ "WHERE sc.userId = :userId AND ul.locId = 1"
+ "GROUP BY l.locName";
namedParameters.addValue("userId", userId);
return jdbc.query(query, namedParameters, new BeanPropertyRowMapper<UserLocation>(UserLocation.class));
}
here schema.sql
CREATE TABLE location (
locId BIGINT NOT NULL PRIMARY KEY AUTO_INCREMENT,
locName VARCHAR(75),
locAddress VARCHAR(255),
locPhone VARCHAR(25),
locEmail VARCHAR(75)
);
CREATE TABLE sec_user (
userId BIGINT NOT NULL PRIMARY KEY AUTO_INCREMENT,
name VARCHAR(75),
lastName VARCHAR(75),
adress VARCHAR(255),
phone VARCHAR(10),
email VARCHAR(75) NOT NULL UNIQUE,
encryptedPassword VARCHAR(128) NOT NULL,
enabled BIT NOT NULL
);
CREATE TABLE coach (
coachId BIGINT NOT NULL PRIMARY KEY AUTO_INCREMENT,
coachName VARCHAR(75),
coachLevel BIGINT,
coachRating BIGINT,
aboutMe VARCHAR(255)
);
CREATE TABLE fitnessClass (
classId BIGINT NOT NULL PRIMARY KEY AUTO_INCREMENT,
className VARCHAR(75),
classPrice DOUBLE
);
CREATE TABLE generalCert (
certId BIGINT NOT NULL PRIMARY KEY AUTO_INCREMENT,
certName VARCHAR(75)
);
CREATE TABLE certCoach (
certId BIGINT NOT NULL,
coachId BIGINT NOT NULL
);
ALTER TABLE certCoach
ADD CONSTRAINT certCoach_FK1 FOREIGN KEY (certId)
REFERENCES generalCert (certId);
ALTER TABLE certCoach
ADD CONSTRAINT certCoach_FK2 FOREIGN KEY (coachId)
REFERENCES coach (coachId);
CREATE TABLE userLocation (
userLocId BIGINT NOT NULL PRIMARY KEY AUTO_INCREMENT,
locId BIGINT NOT NULL,
userId BIGINT NOT NULL,
isHomeLoc BIT,
dayOfVisit DATE
);
ALTER TABLE userLocation
ADD CONSTRAINT userLocation_FK1 FOREIGN KEY (locId)
REFERENCES location (locId);
ALTER TABLE userLocation
ADD CONSTRAINT userLocation_FK2 FOREIGN KEY (userId)
REFERENCES sec_user (userId);
CREATE TABLE amenity (
amenityId BIGINT NOT NULL PRIMARY KEY AUTO_INCREMENT,
amenityName VARCHAR(75),
locId BIGINT
);
ALTER TABLE amenity
ADD CONSTRAINT amenity_FK FOREIGN KEY (locId)
REFERENCES location (locId);
CREATE TABLE room (
roomId BIGINT NOT NULL PRIMARY KEY AUTO_INCREMENT,
roomName VARCHAR(75),
locId BIGINT
);
ALTER TABLE room
ADD CONSTRAINT room_FK FOREIGN KEY (locId)
REFERENCES location (locId);
CREATE TABLE classCoach (
classId BIGINT NOT NULL,
coachId BIGINT NOT NULL
);
ALTER TABLE classCoach
ADD CONSTRAINT classCoachFK1 FOREIGN KEY (classId)
REFERENCES fitnessClass(classId);
ALTER TABLE classCoach
ADD CONSTRAINT classCoachFK2 FOREIGN KEY (coachId)
REFERENCES coach(coachId);
CREATE TABLE schedule (
ScheduleId BIGINT NOT NULL PRIMARY KEY AUTO_INCREMENT,
ScheduleDate DATE,
ScheduleTime TIME,
RoomId BIGINT,
ClassId BIGINT NOT NULL,
LocId BIGINT NOT NULL
);
ALTER TABLE schedule
ADD CONSTRAINT scheduleFK1 FOREIGN KEY (roomId)
REFERENCES room(RoomId);
ALTER TABLE schedule
ADD CONSTRAINT scheduleFK2 FOREIGN KEY (classId)
REFERENCES fitnessClass(classId);
ALTER TABLE schedule
ADD CONSTRAINT ScheduleFK3 FOREIGN KEY (LocId)
REFERENCES location(LocId);
CREATE TABLE reservation (
ClassId BIGINT NOT NULL,
userId BIGINT NOT NULL
);
ALTER TABLE reservation
ADD CONSTRAINT reservationFK1 FOREIGN KEY (classId)
REFERENCES fitnessClass(classId);
ALTER TABLE reservation
ADD CONSTRAINT reservationFK2 FOREIGN KEY (userId)
REFERENCES sec_user(userId);
CREATE TABLE workFrom (
coachId BIGINT NOT NULL,
locId BIGINT NOT NULL
);
ALTER TABLE workFrom
ADD CONSTRAINT workFromFK1 FOREIGN KEY (coachId)
REFERENCES coach(coachId);
ALTER TABLE workFrom
ADD CONSTRAINT workFromFK2 FOREIGN KEY (locId)
REFERENCES location(locId);
CREATE TABLE review (
ReviewId BIGINT NOT NULL PRIMARY KEY AUTO_INCREMENT,
CoachId BIGINT NOT NULL,
userId BIGINT NOT NULL,
ReviewDate DATE,
ComScore CHAR(1),
EnthScore CHAR(1),
PunctScore CHAR(1),
ReviewText VARCHAR(500)
);
ALTER TABLE review
ADD CONSTRAINT reviewFK1 FOREIGN KEY (coachId)
REFERENCES coach(coachId);
ALTER TABLE review
ADD CONSTRAINT reviewFK2 FOREIGN KEY (userId)
REFERENCES sec_user(userId);
CREATE TABLE Reference (
CoachId BIGINT NOT NULL,
userId BIGINT NOT NULL
);
ALTER TABLE Reference
ADD CONSTRAINT ReferenceFK1 FOREIGN KEY (coachId)
REFERENCES coach(coachId);
ALTER TABLE review
ADD CONSTRAINT ReferenceFK2 FOREIGN KEY (userId)
REFERENCES sec_user(userId);
CREATE TABLE ClientCoach (
coachId BIGINT NOT NULL,
userId BIGINT NOT NULL,
myCoach BIT
);
ALTER TABLE ClientCoach
ADD CONSTRAINT ClientCoachFK1 FOREIGN KEY (coachId)
REFERENCES coach(coachId);
ALTER TABLE ClientCoach
ADD CONSTRAINT ClientCoachFK2 FOREIGN KEY (userId)
REFERENCES sec_user(userId);
CREATE TABLE sec_role(
roleId BIGINT NOT NULL PRIMARY KEY AUTO_INCREMENT,
roleName VARCHAR(30) NOT NULL UNIQUE
);
CREATE TABLE user_role
(
id BIGINT NOT NULL PRIMARY KEY AUTO_INCREMENT,
userId BIGINT NOT NULL,
roleId BIGINT NOT NULL
);
ALTER TABLE user_role
ADD CONSTRAINT user_role_uk UNIQUE (userId, roleId);
ALTER TABLE user_role
ADD CONSTRAINT user_role_fk1 FOREIGN KEY (userId)
REFERENCES sec_user (userId);
ALTER TABLE user_role
ADD CONSTRAINT user_role_fk2 FOREIGN KEY (roleId)
REFERENCES sec_role (roleId);
Here the result web page
Here is EERD for the schema
Please try:
SELECT l.locName, COUNT(ul.dayOfVisit) AS numOfVisit -- ...
(to alias numOfVisit), since we are using a BeanPropertyRowMapper (which mapps by "bean properties" (i.e. "field names"): https://www.google.com/search?q=java+bean+naming+conventions).
Alternatively use an other/custom RowMapper.
And since even javadoc recommends:
... For best performance, consider using a custom RowMapper implementation.
Best:
return jdbc.query(query, namedParameters,
(ResultSet rs, int rowNum) -> { // one ResultSet per row:
// column indices start with 1(!):
return new UserLocation(rs.getString(1), rs.getInt(2));
// alternatively (name based): rs.getString("locName")...
}
);
;)
RowMapper javadoc (spring-jdbc:current)
ResultSet javadoc (jdk17)
and since RowMapper is a/meets the requirements of a functional interface, we can write it as lambda expression.

#0001: java.sql.SQLException: Parameter index out of range (1 > number of parameters, which is 0)

I want to delete a row. My TABLES are 'goal' and 'contribute'.It shows above error.
Please tell immediately what's the problem.
Table structure is ,
//goal TABLE
CREATE TABLE `goal` (`id` int(11) NOT NULL AUTO_INCREMENT,
`name` varchar(555) NOT NULL,
`target_value` double NOT NULL,
`target_date` date NOT NULL,
`created_date` datetime NOT NULL,
`status` int(11) NOT NULL,
PRIMARY KEY (`id`))
ENGINE=InnoDB AUTO_INCREMENT=13 DEFAULT CHARSET=utf8
COLLATE=utf8mb4_0900_ai_ci
//Contribute TABLE
CREATE TABLE `contribute`
(`id` int(11) NOT NULL AUTO_INCREMENT,`goal` int(11) NOT NULL,
`amount` double NOT NULL, `date` date NOT NULL,
PRIMARY KEY (`id`),KEY `idgoal_idx` (`goal`),
CONSTRAINT `fk` FOREIGN KEY (`goal`) REFERENCES `goal` (`id`))
ENGINE=InnoDB AUTO_INCREMENT=9 DEFAULT CHARSET=utf8m
COLLATE=utf8mb4_0900_ai_ci
//Code
public static boolean delete(int id) {
try {
Connection con = DB.getConnection();
String sql = "ALTER TABLE 'goal' ADD CONSTRAINT 'fk' FOREIGN
KEY('goal') REFERENCES 'goal' ('id') ON DELETE CASCADE ";
PreparedStatement ps = con.prepareStatement(sql);
ps.setInt(1, id);
ps.executeUpdate();
return true;
} catch (Exception ex) {
ex.printStackTrace();
}
return false;
}
In my oppinion your code is bad. You are executing this
String sql = "ALTER TABLE 'goal' ADD CONSTRAINT 'fk' FOREIGN
KEY('goal') REFERENCES 'goal' ('id') ON DELETE CASCADE ";
every time you invoke this method. You should add constraints when creating the tables.
In order to delete a row from some table i suggest you to create a database procedure or function which does it and invoke it through java.
String sql = "{? = call your_schema.your_package.delete_object(?)}";
try (CallableStatement cs = con.createCallableStatement(sql)) {
cs.setInt(1, id);
cs.executeQuery();
}
This is just an example but i think this is the correct way to do it. In this procedure you accept your ID as parameter and delete the row there.
Here's two problem:
1.your sql doesn't contain any parameter keyword : ?
You use java set parameter ps.setInt(1, id), but your sql doesn't contain keyword ?
Example for parameter using ? :
PreparedStatement p = con.prepareStatement("select * from xxxTable where xxx = ?");
p.setString(1, xxx);
More details you can learn from mysql - java.sql.SQLException Parameter index out of range (1 > number of parameters, which is 0) - Stack Overflow
2.Your SQL maybe wrong
ALTER TABLE 'goal' ADD CONSTRAINT 'fk' FOREIGN
KEY('goal') REFERENCES 'goal' ('id') ON DELETE CASCADE
'goal' table doesn't contain 'goal' column.
it should be changed like:
ALTER TABLE `contribute`
ADD FOREIGN KEY (`goal`) REFERENCES `goal`(`id`) ON DELETE CASCADE ;
SQL Fiddle Demo Link

Phantom MySQLIntegrityConstraintViolationException between two CallableStatementS

We got strange non-permanent error: MySQLIntegrityConstraintViolationException inside java transaction.
Imagine next code:
sql:
CREATE TABLE test (
ruleID INT(11) NOT NULL AUTO_INCREMENT,
name varchar(250),
PRIMARY KEY (ruleID)
) engine=InnoDB;
CREATE TABLE test2 (
ruleID INT(11) NOT NULL,
name varchar(250),
PRIMARY KEY (ruleID),
CONSTRAINT _FK1 FOREIGN KEY (ruleID)
REFERENCES test (ruleID)
ON DELETE CASCADE
) engine=InnoDB;
CREATE PROCEDURE proc1(
inout p_ruleID INT (11),
p_name varchar(250)
)
proc: begin
IF (p_ruleID < 1) THEN
INSERT INTO test (ruleID, name) values (null, p_name);
SELECT LAST_INSERT_ID() INTO p_ruleID;
else
UPDATE test
SET name = p_name
WHERE ruleID = p_ruleID;
SELECT p_ruleID;
END IF;
END //
CREATE PROCEDURE proc2(
p_ruleID INT (11),
p_name varchar(250)
)
BEGIN
DELETE FROM test2
WHERE ruleID = p_ruleID;
INSERT INTO test2(ruleID, name)
VALUES (p_ruleID, p_name);
END //
java:
Connection conn;
int id;
String name;
String subName;
...
conn.setAutoCommit(false);
id=1;
CallableStatement cs1 = conn.prepareCall("{call proc1(?,?)}");
cs1.setInt(1, id);
cs1.setString(2, name);
cs1.registerOutParameter(1, java.sql.Types.INTEGER);
cs1.execute();
int parentID = cs1.getInt(1);
cs1.close();
cs1 = conn.prepareCall("{call proc2(?,?)}");
cs1.setInt(1, parentID);
cs1.setString(2, subName);
cs1.execute();
...
So once during the "cs1.execute()" for "proc2" we got exception:
com.mysql.jdbc.exceptions.jdbc4.MySQLIntegrityConstraintViolationException:
Cannot add or update a child row:
a foreign key constraint fails (test2, CONSTRAINT '_FK1' FOREIGN KEY ('ruleID') REFERENCES 'test' ('ruleID') ON DELETE CASCADE)
We got it only once and can't repeat it.
One "guru" said - java transaction, performed by Connection, don't garanty the visibility of results between CallableStatementS.
Is it true? Or may be the truth is out there?

Oracle JDBC and Views

I am trying to get SELECT statement from a view with executeQuery but i cant get a resultset, the meta data is intact (names and number of columns)
i am also tried change to PreparedStatement and CallableStatement and it is the same
Here is my code
private Statement stmt=null;
private ResultSet rset=null;
........
rset = stmt.executeQuery("SELECT STUDENT_ID,FIRST_NAME,LAST_NAME FROM STUDENT_VIEW");
columnNum=rset.getMetaData().getColumnCount();
toClient.writeInt(columnNum);
for(int i=1;i<=columnNum;i++)
toClient.writeUTF(rset.getMetaData().getColumnName(i));
if (rset.last()) {
toClient.writeInt(rset.getRow());
rset.beforeFirst();
}
while (rset.next())
for(int i=1;i<=columnNum;i++){
if(rset.getString(i)!=null)
toClient.writeUTF(rset.getString(i));
else
toClient.writeUTF(" ");
}
in the debug mode java can't execute rset.last() command
but when i do
rset = stmt.executeQuery("SELECT * FROM STUDENT_VIEW")
the code run perfectly.
Can some one help?
the STUDENT_VIEW
CREATE OR REPLACE VIEW STUDENT_VIEW
AS
SELECT
s.student_id,s.first_name,s.last_name,s.phone,s.birth_date,s.street,
s.zip_code,d.name as Department,d.credits_to_degree,s.credits,s.eligible,c.name as College
FROM
STUDENT s,DEPARTMENT d,COLLEGE c
WHERE
s.department=d.department_id and d.college_id=c.college_id;
The other tables
create table Department (
Department_ID varchar(4) not null,
Name varchar(25) unique,
Department_Head_ID varchar(9),
College_ID varchar(4),
Credits_To_Degree NUMBER(3),
Students NUMBER(3),
Faculty NUMBER(3),constraint pkDepartment primary key (Department_ID));
ALTER TABLE Department ADD FOREIGN KEY (Department_Head_ID) REFERENCES Faculty(Faculty_Id) INITIALLY DEFERRED;
ALTER TABLE Department ADD FOREIGN KEY(College_ID) REFERENCES College(College_ID) INITIALLY DEFERRED;
create table Student (
Student_ID varchar(9) not null,
First_Name varchar(25),
Last_Name varchar(25),
Phone char(11),
Birth_Date date,
Street varchar(100),
Zip_Code char(5),
Department varchar(4),
Credits integer,
Eligible char(4), constraint pkStudent primary key (Student_ID),constraint fkDeptId foreign key (Department) references Department(Department_ID));
create table College(
College_ID varchar(4) not null,
Name varchar(25),
Since date,
Dean_ID varchar(9),constraint pkCollege primary key (College_ID));

CachedRowSet update a record in H2

I have a H2 DB with a table
CREATE TABLE income_expense
(
amount VARCHAR(255) NOT NULL,
name VARCHAR(255) NOT NULL,
ondate VARCHAR(255) NOT NULL
);
and some random data like INSERT INTO income_expense VALUES ('10','Something','2015-04-15');
then I connect to this DB with JDBC and try to do an UPDATE through CachedRowSet:
public void doUpdate()
{
try
{
Class.forName("org.h2.Driver");
setConnection(
DriverManager.getConnection("jdbc:h2:~/thisdb", "sa", ""));
CachedRowSet crs2 = new CachedRowSetImpl();
crs2.setType(CachedRowSet.TYPE_SCROLL_INSENSITIVE);
crs2.setConcurrency(CachedRowSet.CONCUR_UPDATABLE);
crs2.setCommand(
"SELECT amount, name, ondate FROM income_expense");
crs2.execute(getConnection());
crs2.absolute(1);
crs2.updateString("amount", "22");
crs2.updateString("name" , "33");
crs2.updateString("ondate", "44");
crs2.updateRow();
crs2.acceptChanges();
}
catch (ClassNotFoundException | SQLException e)
{
System.out.println("Error occured." + e);
}
}
this update fails with a message javax.sql.rowset.spi.SyncProviderException: 1 conflicts while synchronizing.
What am I doing wrong to update a record?
Well... CachedRowSet UPDATE worked only after I added a PRIMARY KEY to the table:
ALTER TABLE income_expenses ADD COLUMN id INT NOT NULL AUTO_INCREMENT;
ALTER TABLE income_expenses ADD CONSTRAINT PRIMARY KEY (id);
and specified numbers of columns which form a key for uniquely identifying a row and included that column in a SELECT:
//First column from a command will be the key
crs2.setKeyColumns(new int[]{1});
crs2.setCommand("SELECT id, amount, name, ondate FROM income_expense");

Categories

Resources