As the commenters have already said, the error tells you the problem. A “foreign key constraint” violation means you tried to insert a row into a child table using a foreign key value for a parent row that does not exist.
So you need to examine the data in the parent table (Employee) and the values you are attempting to insert into the child table (Attendance). You have a mismatch.
Below is an entire working example, creating a database & inserting rows, all crammed into a single class. While this is not production-worthy code, it is a working demonstration of inserting child rows both properly (three times) and improperly (once, last line of demo
method).
The point of the demo is the four calls to insertAttendance
in the demo
method. We are given employee_
rows with identifiers of 1, 2, and 3. So inserting attendance_
rows for any of those three values succeeds.
this.insertAttendance ( conn , 2 …
this.insertAttendance ( conn , 1 …
this.insertAttendance ( conn , 3 …
When we try an invalid number for which we have no such employee_
, such as 4
, then we fail. We get a SQLException noting a violation of the foreign key constraint. The database is doing its job in enforcing referential integrity. If we were not blocked we would be creating an “orphan” row, an attendance_
row with no matching employee_
row.
this.insertAttendance ( conn , 4 … // Throws SQLException for violation of the foreign key constraint.
This example uses the pure Java database, H2 Database. You must add as a dependency to run this code. Easy to add via Maven, etc.
When run.
Tables established and populated.
Table dump: employee_
Employee id_: 1 | name_: Alfred
Employee id_: 2 | name_: Barbara
Employee id_: 3 | name_: Charlie
Table dump: attendance_
Attendance id_: 1 | fkey_employee_id_: 2 | when_expected_: 2016-01-23T10:00:00Z | status_: present
Attendance id_: 2 | fkey_employee_id_: 1 | when_expected_: 2016-01-23T10:00:00Z | status_: present
Attendance id_: 3 | fkey_employee_id_: 3 | when_expected_: 2016-01-23T10:00:00Z | status_: absent
SQLException: Referential integrity constraint violation: "CONSTRAINT_32: PUBLIC.ATTENDANCE_ FOREIGN KEY(FKEY_EMPLOYEE_ID_) REFERENCES PUBLIC.EMPLOYEE_(ID_) (4)"; SQL statement:
INSERT INTO attendance_ ( fkey_employee_id_ , when_expected_ , status_ ) VALUES ( ? , ? , ? ); [23506-191]
Example code.
package com.example.h2example;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.time.Instant;
/**
* Demonstrates how to both properly and improperly insert rows into a child
* table.
*
* Caveat: Not production-worthy code. For demonstration purposes only. Use at
* your own risk.
*
* @author Basil Bourque
*/
public class App {
public static void main ( String[] args ) {
App app = new App ();
app.demo ();
}
private void demo () {
Connection conn = this.fetchConnection ();
this.insertAttendance ( conn , 2 , Instant.parse ( "2016-01-23T10:00:00Z" ) , "present" );
this.insertAttendance ( conn , 1 , Instant.parse ( "2016-01-23T10:00:00Z" ) , "present" );
this.insertAttendance ( conn , 3 , Instant.parse ( "2016-01-23T10:00:00Z" ) , "absent" );
this.dumpTable_Employee ( conn );
this.dumpTable_Attendance ( conn );
// Insert invalid value (BAD).
this.insertAttendance ( conn , 4 , Instant.parse ( "2016-01-23T10:00:00Z" ) , "absent" );
}
private Connection fetchConnection () {
Connection conn = null;
try {
Class.forName ( "org.h2.Driver" );
} catch ( ClassNotFoundException e ) {
// TODO: Handle exception.
System.out.println ( "Database failure: " + e );
return null;
}
// Specify a database named 'EmployeeAttendanceBogus.mv.db' in the Unix user’s home folder.
String dbFolderPath = "~/";
String dbName = "EmployeeAttendanceBogus";
String dbUrl = "jdbc:h2:" + dbFolderPath + dbName;
String dbUserName = "h2";
String dbPassword = "pw";
try {
// If database does not yet exist, it is automatically created.
conn = DriverManager.getConnection ( dbUrl , dbUserName , dbPassword );
} catch ( SQLException ex ) {
System.out.println ( "SQLException on DriverManager.getConnection: " + ex.getMessage () );
// TODO: Handle exception when no Connection is made.
}
if ( null == conn ) {
System.out.println ( "Database error. No Connection." );
// TODO: Handle exception when no Connection is made.
} else {
// ELSE got database connection. Normal.
this.recreateTables ( conn );
// this.dumpTable_Employee ( conn );
// this.dumpTable_Attendance ( conn );
}
return conn;
}
private void recreateTables ( Connection conn ) {
// Update database structure if needed.
StringBuilder sql = new StringBuilder ();
// Delete any existing tables.
sql.append ( "DROP TABLE IF EXISTS attendance_ ; " + " \n" ); // Drop child table first, because of referential integrity.
sql.append ( "DROP TABLE IF EXISTS employee_ ; " + " \n" );
// Define tables.
sql.append ( "CREATE TABLE employee_ " + " \n" );
sql.append ( "(" + " \n" );
sql.append ( "id_ IDENTITY PRIMARY KEY , " + " \n" ); // Primary key, Long type.
sql.append ( "name_ VARCHAR_IGNORECASE NOT NULL " + " \n" );
sql.append ( ")" + " \n" );
sql.append ( ";" + " \n" );
sql.append ( "" );
sql.append ( "CREATE TABLE attendance_ " + " \n" );
sql.append ( "(" + " \n" );
sql.append ( "id_ IDENTITY PRIMARY KEY , " + " \n" ); // Primary key, Long type.
sql.append ( "fkey_employee_id_ BIGINT , " + " \n" );
sql.append ( "when_expected_ TIMESTAMP NOT NULL , " + " \n" );
sql.append ( "status_ VARCHAR_IGNORECASE NOT NULL " + " \n" ); // Domain: "present" | "absent" .
sql.append ( ")" + " \n" );
sql.append ( ";" + " \n" );
sql.append ( "" );
sql.append ( "ALTER TABLE attendance_ ADD FOREIGN KEY ( fkey_employee_id_ ) REFERENCES employee_( id_ ) ;" );
sql.append ( "" );
sql.append ( "INSERT INTO employee_ ( name_ ) VALUES ( 'Alfred' ) ;" );
sql.append ( "INSERT INTO employee_ ( name_ ) VALUES ( 'Barbara' ) ;" );
sql.append ( "INSERT INTO employee_ ( name_ ) VALUES ( 'Charlie' ) ;" );
System.out.println ( "Tables established and populated.\n" );
try ( Statement stmt = conn.createStatement () ) {
stmt.executeUpdate ( sql.toString () );
} catch ( SQLException ex ) {
System.err.println ( "SQLException: " + ex.getMessage () );
// TODO: Handle exception.
}
}
private void dumpTable_Employee ( Connection conn ) {
StringBuilder sql = new StringBuilder ();
sql.append ( "SELECT * FROM employee_ ;" );
try ( PreparedStatement pstmt = conn.prepareStatement ( sql.toString () ) ) {
try ( ResultSet rs = pstmt.executeQuery (); ) {
System.out.println ( "Table dump: employee_" );
while ( rs.next () ) {
long id = rs.getLong ( "id_" );
String name = rs.getString ( "name_" );
System.out.println ( "Employee id_: " + id + " | name_: " + name );
}
System.out.println ( "" );
}
} catch ( SQLException ex ) {
System.err.println ( "SQLException: " + ex.getMessage () );
// TODO: Handle exception.
}
}
private void dumpTable_Attendance ( Connection conn ) {
StringBuilder sql = new StringBuilder ();
sql.append ( "SELECT * FROM attendance_ ;" );
try ( PreparedStatement pstmt = conn.prepareStatement ( sql.toString () ) ) {
try ( ResultSet rs = pstmt.executeQuery (); ) {
System.out.println ( "Table dump: attendance_" );
while ( rs.next () ) {
long id = rs.getLong ( "id_" );
long fkey = rs.getLong ( "fkey_employee_id_" );
java.sql.Timestamp whenExpectedTs = rs.getTimestamp ( "when_expected_" );
Instant whenExpected = whenExpectedTs.toInstant (); // Convert as soon as possible from java.sql.Timestamp to java.time.
String status = rs.getString ( "status_" );
System.out.println ( "Attendance id_: " + id + " | fkey_employee_id_: " + fkey + " | when_expected_: " + whenExpected + " | status_: " + status );
}
System.out.println ( "" );
}
} catch ( SQLException ex ) {
System.err.println ( "SQLException: " + ex.getMessage () );
// TODO: Handle exception.
}
}
private void insertAttendance ( Connection conn , long employeeId , Instant whenExpected , String status ) {
StringBuilder sql = new StringBuilder ();
sql.append ( "INSERT INTO attendance_ ( fkey_employee_id_ , when_expected_ , status_ ) VALUES ( ? , ? , ? );" );
try ( PreparedStatement pstmt = conn.prepareStatement ( sql.toString () ) ) {
pstmt.setLong ( 1 , employeeId );
pstmt.setTimestamp ( 2 , java.sql.Timestamp.from ( whenExpected ) );
pstmt.setString ( 3 , status );
int rowsAffected = pstmt.executeUpdate ();
} catch ( SQLException ex ) {
System.err.println ( "SQLException: " + ex.getMessage () );
// TODO: Handle exception.
}
}
}
By the way…
Your code shows you may be confused about java.util.Date
and java.sql.Date
. The first is a date and time-of-day while the second pretends to be only a date without time-of-day.
Avoid the old java.util.Date class (and .Calendar) as it is poorly designed, confusing, and troublesome. Use java.time instead, built into Java 8 and later.
The java.sql types are just as bad. But we must continue to use them until our JDBC drivers are updated to directly use java.time types. Until then use java.sql types as briefly as possible to move data in/out of database. Convert from java.sql to java.time immediately after receiving a value.