I've got tables like this:
Table A:
`id | name`
Table B:
`id | A_id | ....`
A_id is a foreign key to Table A, the Engine is InnoDB
This is the code that fails:
String[] cleanupQueries = new String[] { "DELETE FROM B WHERE A_id = (SELECT id FROM A WHERE name = 'test')",
"DELETE FROM A WHERE name = 'test'" };
Connection connection;
try {
connection = DriverManager.getConnection(getConnectionString());
connection.setAutoCommit(false);
} catch (SQLException e) {
throw new RuntimeException("Error establishing a database connection!");
}
try {
for(String cleanupQuery : cleanupQueries) {
PreparedStatement statement = connection.prepareStatement(cleanupQuery);
statement.executeUpdate(); //FAILS WHEN EXECUTING THE SECOND QUERY
}
} catch(SQLException e) {
throw new RuntimeException("Error while executing the queries in the transactional context!");
}
try {
connection.commit();
} catch (SQLException e) {
rollback(connection);
throw new RuntimeException("Error while comitting!");
}
The Exception i get is:
com.mysql.jdbc.exceptions.jdbc4.MySQLIntegrityConstraintViolationException: Cannot delete or update a parent row: a foreign key constraint fails ('DATABASE/TABLE', CONSTRAINT 'FK_B_A' FOREIGN KEY ('FK_A') REFERENCES 'A' ('ID') ON DEL)
The database doesn't let me delete A while there are still B's left, but the first query deleted all B's. I want to delete all B's and the A they reference only completely.
I don't want to change the Tables to have cascading deletes. What shall i do to get the code working?
Cause for error is
The Foreign Key has referenced to the table A id so if you would like to delete the F_Key , first you should delete the Child references values of that foreign keys then only its possible to delete the parent.
Correct me if 'm wrong..
Simply add the cascade is true while deleting the foreign key constraint.The child table entry is automatically deleted when you delete the original parent entry.
Try:
"DELETE FROM B WHERE A_id = (SELECT id FROM A WHERE name IN 'test')"
Since the child rows are deleted in the same transaction, the deleted rows are still visible and thus the parent rows could not be deleted.
This may be because of the transaction isolation setting on the connection. I would try different levels and see which one allows it.
Related
I am making a javafx (intelliJ with java jdk 11) app using SQLite version 3.30.1 with DB Browser for SQLite.
I have a table called "beehives" and each beehive can have diseases (stored in the table "diseases").
this is my "beehives" table:
CREATE TABLE "beehives" (
"number" INTEGER NOT NULL,
"id_apiary" INTEGER NOT NULL DEFAULT -2,
"date" DATE,
"type" TEXT,
"favorite" BOOLEAN DEFAULT 'false',
PRIMARY KEY("number","id_apiary"),
FOREIGN KEY("id_apiary") REFERENCES "apiaries"("id") ON DELETE SET NULL
);
this is my "diseases" table:
CREATE TABLE "diseases" (
"id" INTEGER NOT NULL,
"id_beehive" INTEGER NOT NULL,
"id_apiary" INTEGER NOT NULL,
"disease" TEXT NOT NULL,
"treatment" TEXT NOT NULL,
"start_treat_date" DATE NOT NULL,
"end_treat_date" DATE,
PRIMARY KEY("id"),
FOREIGN KEY("id_beehive","id_apiary") REFERENCES "beehives"("number","id_apiary") ON UPDATE CASCADE
);
this is my "apiaries" table in case you need it:
CREATE TABLE "apiaries" (
"id" INTEGER NOT NULL,
"name" TEXT NOT NULL,
"address" TEXT,
PRIMARY KEY("id")
);
Everything works fine, but when I update a beehive (for example when I update the "number", which is the primary key in beehives table) the diseases does not update the number. The result is that the diseases get some kind of disconnected since the beehive change his "number" correctly, but the disease doesn't update it. There is no error message.
My java method that calls the update is:
public void updateBeehiveInDB(Beehives newBeehive,Beehives oldBeehive){
try {
s = "UPDATE beehives SET number=?, id_apiary=?, date=?, type=?, favorite=? WHERE number=? and id_apiary=? ";
preparedStatement = connection.prepareStatement(s);
preparedStatement.setInt(1, newBeehive.getNumber());
preparedStatement.setInt(2, newBeehive.getId_apiary());
preparedStatement.setDate(3, newBeehive.getDate());
preparedStatement.setString(4, newBeehive.getType());
preparedStatement.setBoolean(5, newBeehive.isFavorite());
preparedStatement.setInt(6, oldBeehive.getNumber());
preparedStatement.setInt(7,oldBeehive.getId_apiary());
int i = preparedStatement.executeUpdate();
} catch (SQLException e) {
e.printStackTrace();
}
}
I tried to check if foreign keys are "on" following the SQLite documentation here, but my English is not good enough and I am using DB Manager. So no idea how to check if this is on, or how to turn it on manually.
What can I do to update the diseases "id_beehives" when I update "number" on beehives table?
The problem was that i am using a composite foreign key and i need to implement it correctly on other tables too even if i was not using them yet in this new project. Was very hard to find the problem because intellij normally show all the SQL error messages, but in this case, it was not showing anything. But when i tried to do the SQL sentence manually in the DB Browser, there i got an error message and was able to fix it.
Also had to activate foreign key on the connection:
public Connection openConnection() {
try {
String dbPath = "jdbc:sqlite:resources/db/datab.db";
Class.forName("org.sqlite.JDBC");
SQLiteConfig config = new SQLiteConfig();
config.enforceForeignKeys(true);
connection = DriverManager.getConnection(dbPath,config.toProperties());
return connection;
} catch (ClassNotFoundException e) {
e.printStackTrace();
} catch (SQLException e) {
e.printStackTrace();
}
return null;
}
I'm working at some school project and my job here is to make a delete button for that list view in Java FX, but the problem is that when i want to proceed that it shows me this error. I tried some solutions, but none of them worked.
so here's the code
#FXML
private void removeStudentOnClick(ActionEvent event) throws IOException, SQLException{
ModelEditStudent student=(ModelEditStudent)tables.getSelectionModel().getSelectedItem();
String sql="DELETE FROM student WHERE nr_indeksu=?";
Alert alert = new Alert(Alert.AlertType.CONFIRMATION);
alert.setTitle("Usuwanie studenta");
alert.setHeaderText(null);
alert.setContentText("Czy na pewno chcesz usunÄ…c tego studenta z listy?");
Optional <ButtonType> action = alert.showAndWait();
if(action.get() == ButtonType.OK){
tables.getItems().removeAll(tables.getSelectionModel().getSelectedItem());
try{
try (Connection myConn = ConnectionManager.getConnection()) {
try (PreparedStatement st = myConn.prepareStatement(sql)) {
st.setString(1, student.getNr_indeksu());
st.executeUpdate();
}
myConn.close();
}
}catch (SQLException e){
System.out.println(e);
}
}
and there's the error:
com.mysql.jdbc.exceptions.jdbc4.MySQLIntegrityConstraintViolationException:
Cannot delete or update a parent row: a foreign key constraint fails
(`wu`.`oceny`, CONSTRAINT `oceny_ibfk_3` FOREIGN KEY (`nr_indeksu`)
REFERENCES `student` (`nr_indeksu`))
All the point of this operation is about selecting the row and removing from the database after pressing a button. By now it works only for the listview, but it doesn't remove records from the database.
Anyone got an idea how make it work?
I believe the problem is in your DB schema. try fixing the foreign keys dependencies.I mean the value of nr_indeksu exists in another table of your DB.
You have a table called oceny which has a column nr_indeksu that contains student ids. You have created a foreign key constraint on that table, which requires those student ids to match up with something in the student table.
If you try to delete something in the student table that's referenced by the oceny table, you will get this error, because otherwise, it would leave the database in a state where the oceny table references a student that doesn't exist.
There are a number of solutions to this. You will need to think about what should actually happen in this case - what do you want to have happen to the oceny rows when you delete a matching student.
One option would be for you to change the foreign key to make it do a "cascade delete" - that is, the oceny automatically gets deleted in the same transaction as the student. There's some information here on how to do that.
I have three tables in my database:
First one of COMPANY that includes id, name and email.
Second - COUPON that includes id, title, dates, price etc...
Third - join table COMPANY_COUPON that includes id of the companies and id of the coupons which they own.
In java, I have a method that deletes expired coupons using:
DELETE FROM COUPON WHERE END_DATE < CURRENT_DATE
But after deleting expired coupons, I still have their id in COMPANY_ COUPON join table, how can I solve this?
#Override
public void removeExpiredCoupons() throws CouponSystemException {
String delete = "DELETE FROM COUPON WHERE END_DATE < CURRENT_DATE";
Connection connection = pool.getConnection();
try (PreparedStatement pstmt = connection.prepareStatement(delete)) {
pstmt.executeUpdate();
// This line can be removed
System.out.println("All expired coupos are removed.");
} catch (SQLException e) {
throw new CouponSystemException("Removing expired coupons is failed. ", e);
} finally {
pool.returnConnection(connection);
}
}
It sounds like you currently have no foreign key constraints defined from COMPANY_COUPON to COUPON (nor to COMPANY). That is undesirable, because it results exactly in the problem you describe.
If you want records in COMPANY_COUPON to get automatically deleted if the record is deleted, you need to define a foreign key constraint from COMPANY_COUPON to COUPON and make it on delete cascade.
For example you can add one with
alter table COMPANY_COUPON
add constraint fk_company_coupon_coupon
foreign key (COUPON_ID) references COUPON (ID) on delete cascade
You should do something similar to COMPANY.
you COULD:
delete the records in the company_coupon table before deleting the records in the coupon table:
first get a list of the expired id's by retrieving result set of expired id's:
select id from coupon where END_DATE < CURRENT_DATE
then loop through the result set to delete records of each id:
delete from company_coupon where id = idFromLoop
lastly delete the records from the coupon table:
delete from coupon where END_DATE < CURRENT_DATE
you SHOULD:
google "foreign key on delete cascade" to see how to use a foreign key to delete associated records across tables.
(source: hostingpics.net)
how can I add a new customer or supplier?, last time I was using this class for one table "customer":
Code:
public int addnewcustomer(){
int idcust;
DBConnection eConnexion = new DBConnection();
try {
//Statement state = eConnexion.getConnexion().createStatement();
String sql = "INSERT INTO customer(name_cust, num_cust, adress_cust, city_cust , tel_cust, ref_cust)";
sql+= "VALUES (?,?,?,?,?,?)";
PreparedStatement insertQuery = eConnexion.getConnexion().prepareStatement(sql);
insertQuery.setString(1,Name_cust);
insertQuery.setString(2,Num_cust);
insertQuery.setString(3,Adress_cust);
insertQuery.setString(4,City_cust );
insertQuery.setString(5,Tel_cust);
insertQuery.setString(6,Ref_cust);
insertQuery.executeUpdate();
} catch (SQLException e) {
e.printStackTrace();
//JOptionPane.showMessageDialog(null,"Erreur:the addition is not performed with Succee!");
idcust = 0;
}
eConnexion.closeConnection();
idcust= Services.getLastInsertedId("customer","id_customer");
return idcust;
}
Currently, I attach all tables with new table "person". All tables now extend "person", I tried to add new customer with super variables "person" but I'm stuck in filling foreign key "id_pers FK".
First you need to persist a person into your database. After a successful(!) persist, you can query for the id the database used to insert the data. Most databases also provide a method to directly retrieve the used id after an insert.
After you have successfully persisted the person you can use the id for the foreign key column.
You may consider using a transaction for these actions, as there should never be a person persisted without a customer/employee whatever extending the persons data.
With a transaction, you can rollback the previous actions, for example if something goes wrong during the insertion of the customer.
I am trying to catch MysqlIntegrityException in catch clause of SQL exception but it does not seems to handle it in catch block of SQL exception. What might be the reason and how to solve it.
catch(SQLException e)
{
//not reaching here
}
Sorry, cannot reproduce this one.
Here's some tables I created in the MySQL monitor:
mysql> create table a (id int not null primary key auto_increment);
Query OK, 0 rows affected (0.09 sec)
mysql> create table b (b_id int not null primary key auto_increment, a_id int not null);
Query OK, 0 rows affected (0.06 sec)
mysql> alter table b add constraint a_fk foreign key (a_id) references a(id);
Query OK, 0 rows affected (0.19 sec)
Records: 0 Duplicates: 0 Warnings: 0
mysql> insert into a() values();
Query OK, 1 row affected (0.04 sec)
mysql> insert into a() values();
Query OK, 1 row affected (0.03 sec)
mysql> insert into b (a_id) values (1);
Query OK, 1 row affected (0.04 sec)
Let's just test that the foreign key constraint is working:
mysql> delete from a where id = 1;
ERROR 1451 (23000): Cannot delete or update a parent row: a foreign key constraint fails (`test`.`b`, CONSTRAINT `a_fk` FOREIGN KEY (`a_id`) REFERENCES `a` (`id`))
I then wrote this Java class:
import java.sql.*;
public class MySQLExceptionTest {
public static void main(String[] args) throws Exception {
DriverManager.registerDriver(new com.mysql.jdbc.Driver());
Connection c = DriverManager.getConnection("jdbc:mysql://localhost:3306/test", "user", "password");
PreparedStatement stmt = c.prepareStatement("DELETE FROM a WHERE id = 1");
try {
stmt.execute();
}
catch (SQLException e) {
System.out.println("Got a " + e.getClass().getName() + " with message " + e.getMessage());
}
}
}
When I ran this class, I got the following output:
Got a com.mysql.jdbc.exceptions.jdbc4.MySQLIntegrityConstraintViolationException with message Cannot delete or update a parent row: a foreign key constraint fails (`test`.`b`, CONSTRAINT `a_fk` FOREIGN KEY (`a_id`) REFERENCES `a` (`id`))
My code can catch this exception, so why can't yours? Well, with the almost total absence of any of your code, I can only offer a couple of speculative answers:
the exception is caught somewhere inside the try block and perhaps wrapped and rethrown,
the code in the try block starts a new Thread, and the exception is thrown in the new thread.