I have an application that I am working on that will query a database and display the results. The program also makes changes to the database (update, delete, insert). I had most of these features working correctly until recently when I made some changes. Now I am getting an SQLException that tells me I am violating a foreign key constraint. I have looked it up and found out that the violation is a result of more than one table sharing data. Is there a way to overcome this? How would I make the update without violating the constraint? here is my update method:
InstructorEditorPanel updateEditorPanel = new InstructorEditorPanel();
updateEditorPanel.setFieldText(InstructorEditorPanel.FieldTitle.B_NUMBER, updBNumber);
updateEditorPanel.setFieldText(InstructorEditorPanel.FieldTitle.FIRST_NAME, updFName);
updateEditorPanel.setFieldText(InstructorEditorPanel.FieldTitle.LAST_NAME, updLName);
int result = JOptionPane.showConfirmDialog(null, updateEditorPanel,
"Update Instructor", JOptionPane.OK_CANCEL_OPTION,JOptionPane.PLAIN_MESSAGE);
if(result == JOptionPane.OK_OPTION)
{
for (InstructorEditorPanel.FieldTitle fieldTitle : InstructorEditorPanel.FieldTitle
.values()) {
bNum = getBNumber(updateEditorPanel.getFieldText(fieldTitle.values()[0]));
fName = getFirstName(updateEditorPanel.getFieldText(fieldTitle.values()[1]));
lName = getLastName(updateEditorPanel.getFieldText(fieldTitle.values()[2]));
}
try
{
connection = DriverManager.getConnection(URL);
updateInstructor = connection.prepareStatement(
"UPDATE Instructor SET BNUMBER = ?, FIRSTNAME = ?, LASTNAME = ? WHERE BNUMBER = ?");
}catch(SQLException sqlException){
sqlException.printStackTrace();
System.exit(1);
}//end catch
try
{
updateInstructor.setString(1, bNum);
updateInstructor.setString(2, fName);
updateInstructor.setString(3, lName);
updateInstructor.setString(4,mNumber);
updateInstructor.executeUpdate();
}catch(SQLException sqlException){
sqlException.printStackTrace();
}//end of catch
finally
{
close();
}//end
}
Display(panel); }
I had the method working without any problems until recently when I made some changes. I don't know what I did, but now I am getting the foreign key constraint violated exception
here is the exception:java.sql.SQLIntegrityConstraintViolationException: UPDATE on table 'INSTRUCTOR' caused a violation of foreign key constraint 'SQL120408141918440' for key (1234500000). The statement has been rolled back.
database info
CREATE TABLE Instructor (
BNumber varchar(10) NOT NULL,
FirstName varchar(20),
LastName varchar(30),
PRIMARY KEY (BNumber)
);
CREATE TABLE Section (
CRN int NOT NULL,
Term varchar(6) NOT NULL,
SectionNumber varchar(3),
CourseID varchar(9),
Enrollment smallint,
BNumber varchar(10),
PercentResp numeric(5,2),
CONSTRAINT CRN_Term PRIMARY KEY (CRN,Term),
FOREIGN KEY (CourseID) REFERENCES Course (CourseID),
FOREIGN KEY (BNumber) REFERENCES Instructor (BNumber)
);
INSERT INTO Instructor (BNumber, FirstName, LastName)
VALUES
('0000012345','Bill','Smith'),
('0000023456','Sue','Taylor'),
('0000034567','Skilar','Ramsey'),
('1234500000','Sam','Jones'),
('2345600000','Tyson','Quilez');
INSERT INTO Section (CRN, Term, SectionNumber, CourseID, Enrollment,
BNumber, PercentResp)
VALUES
(40035,'201040','02B','CHM2210', 31,'0000034567',100),
(40001,'201040','02B','CGS1000', 27,'0000012345',100),
(40002,'201040','70B','CGS2100', 25,'0000012345',100),
(40003,'201040','71B','CGS2100', 19,'0000012345',100),
(40004,'201040','01B','COP1000', 15,'0000012345',100),
(40030,'201040','01B','BSCC1005',30,'0000023456',100),
(40031,'201040','02B','BSCC1005',25,'0000023456',100),
(40032,'201040','70B','BSCC1005',24,'0000023456',100),
(40000,'201040','01B','CGS1000', 15,'0000012345',100),
(40034,'201040','01B','CHM2210', 27,'0000034567',100);
Replace
"UPDATE Instructor SET BNUMBER = ?, FIRSTNAME = ?, LASTNAME = ? WHERE BNUMBER = ?"
With
"UPDATE Instructor SET FIRSTNAME = ?, LASTNAME = ? WHERE BNUMBER = ?"
You should not update the primary key if it's the matching condition in your update query.
You should put ON UPDATE CASCADE after the references
Related
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
Go easy on me, middle school teacher taking a CS class. I've got a Java program that asks for user name, height, weight, does some calculations and gives results to the user. I now need to store this data in a database. I can get the data to store until I start using primary and foreign keys.
Here is the error I can't figure out:
Error: java.sql.SQLIntegrityConstraintViolationException: The statement was aborted because it would have caused a duplicate key value in a unique or primary key constraint or unique index identified by 'SQL180429151131780' defined on 'USERPROFILE'.
Here is my table:
drop table stayfitapp.userdata;
drop table stayfitapp.userprofile;
drop schema stayfitapp restrict;
create schema stayfitapp;
create table stayfitapp.userprofile
(
profileName varchar(255) not null primary key,
profileGender varchar(255) not null
);
create table stayfitapp.userdata
(
profileAge double not null,
profileWeight double not null,
profileHeight double not null,
profileWaistCircumference double not null,
profileHipCircumference double not null,
profileName varchar(255),
foreign key (profileName) references stayfitapp.userprofile(profileName)
);
Here is the section of the "app" that writes to the table...
public void save(){
try {
String query = "insert into stayfitapp.userprofile" + "(profileName, profileGender)" + "values" + "(?,?)";
String query2 = "insert into stayfitapp.userdata" + "(profileAge, profileWeight, profileHeight, profileWaistCircumference, profileHipCircumference)" + "values" + "(?,?,?,?,?)";
Connection myConnection = DriverManager.getConnection("jdbc:derby://localhost:1527/stayfitDB2", "username", "password");
Statement myStatement = myConnection.createStatement();
//Statement myStatement2 = myConnection.createStatement();
PreparedStatement prepared = myConnection.prepareStatement(query);
prepared.setString(1, profileName);
prepared.setString(2, profileGender);
PreparedStatement prepared2 = myConnection.prepareStatement(query2);
prepared2.setDouble(1, profileAge);
prepared2.setDouble(2, profileWeight);
prepared2.setDouble(3, profileHeight);
prepared2.setDouble(4, profileWaistCircumference);
prepared2.setDouble(5, profileHipCircumference);
int rowsAffected = prepared.executeUpdate();
int rowsAffected2 = prepared2.executeUpdate();
if(rowsAffected==0)
{
System.out.println("Warning: User data did not save!");
}
else
{
System.out.println("User info saved!");
}
}
catch(SQLException e)
{
System.out.println("Error: "+e.toString());
}
Your save() method will attempt to add the user to the stayfitapp.userprofile table. This table has a field called profileName. profileName is the "primary key" so no duplicate values are allowed.
The error that you are getting is saying that you cannot add(insert) the record to the table because the table already has a record with the same name.
Does your program work okay if you use a different name each time?
You will need to add some logic to your program to deal with the scenario where the profileName already exists in the table. This will probably involve deleting or updating the existing record.
This is the problem.
insert into stayfitapp.userprofile"
+ "(profileName, profileGender)" + "values" , etc
You have nothing to check to see if a record already exists. Something like this would work better.
insert into stayfitapp.userprofile
profileName, profileGender
select distinct ?, ?
from someSmallTable
where not exists (
select 1
from stayfitapp.userprofile
where profileName = ?
)
The someSmallTable bit depends on your database engine, which you didn't specify.
I ended up writing a method to check if the username was already in the profile table. If the username was a duplicate I only wrote to the data table. If the username was new I wrote to both tables.
Thank you for your help! I'm sure there was a more efficient method (figuratively and literally) but I'm on to my final project and nearly surviving an actual CS class.
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?
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));
I'm trying to update a table with prepared statement, but I get the error:
ERROR fremad.dao.JdbcUserDao - com.mysql.jdbc.exceptions.jdbc4.MySQLIntegrityConstraintViolationException: Duplicate entry '21' for key 'PRIMARY'
I really don't get it because I'm not trying to add more rows.
This is the table:
CREATE TABLE `user_meta` (
`user_id` INT(16) NOT NULL ,
`first_name` VARCHAR(32) NOT NULL ,
`last_name` VARCHAR(32) NOT NULL ,
`phone_number` VARCHAR(16) ,
`birthday` DATE ,
`home_town` VARCHAR(32) ,
`profession` VARCHAR(32) ,
CONSTRAINT `fk_user_meta_id` FOREIGN KEY (`user_id`) REFERENCES `user` (`id`),
PRIMARY KEY ( `user_id` )
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
This is the function:
#Override
public UserMetaObject updateUserMeta(UserMetaObject userMetaObject) {
String sql = "UPDATE " + SqlTablesConstants.SQL_TABLE_NAME_USER_META + " SET "
+ "first_name = ?, "
+ "last_name = ?, "
+ "phone_number = ?, "
+ "birthday = ?, "
+ "home_town = ?, "
+ "profession = ? "
+ "WHERE user_id = ?";
connect();
try {
prpstm = conn.prepareStatement(sql);
prpstm.setString(1, userMetaObject.getFirstName());
prpstm.setString(2, userMetaObject.getLastName());
prpstm.setString(3, userMetaObject.getPhoneNumber());
prpstm.setDate(4,userMetaObject.getBirthday());
prpstm.setString(5, userMetaObject.getHomeTown());
prpstm.setString(6, userMetaObject.getProfession());
prpstm.setInt(7, userMetaObject.getUserId());
prpstm.executeUpdate();
} catch (SQLException e) {
LOG.error(e.toString());
return null;
} finally {
close();
}
return userMetaObject;
}
And when I tried to paste this directly in to the terminal and it succeeded:
UPDATE user_meta SET first_name = "John", last_name = "Doe", phone_number = "81549300", birthday = "1988-05-24 00:00:00", homeTown = "Lillehammer", profession="Student" WHERE user_id = 21;
What am I doing wrong? Please tell me if you need any more info..
When you tried your query in console there was user_id=5, but you get exception with user_id=21. It seems that you already has row with user_id=21!
When I have strange behaviors like this, it is common that the problem might be related to some trigger that you might not be aware of, if not, I would suspect from the fact that your primary key is also a foreign key, some databases have problems with that.