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.
Related
I have 2 tables; 1 named student and 1 named student_course. I want to delete an entry using the student ID which is the same for both tables, but an student can or can not be enrolled in a course meaning they are not in the table student_course. How do I delete the student from both tables or just from the student table if he is not in any course?
This is what I have in mind:
String sql = "DELETE FROM student, student_course" +
"USING student INNER JOIN student_course" +
"ON student.student_id = student_course.student_id" +
"WHERE student.student_id =?";
In Postgres, you can delete from multiple tables using CTEs:
with d as (
delete from student_course sc
where sc.student_id = ?
)
delete s from student s
where s.student_id = ?
You can make use of the ON DELETE CASCADE option on the foreignkey. If you specify the foreign key like this:
ALTER TABLE student_course
ADD FOREIGN KEY (student_id) REFERENCES student(student_id) on delete cascade;
it automatically deletes your records in student_course if you delete records in students.
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.
Select a list and update the records one by one according to some field value .How to avoid duplicate update and insert ?
public void takeOrder(String currentUser){
String sql = "select * from customer where take_status is null limit 30";
List<Customer> customerList = customerDao.findUnTakeCustomer(sql);
for(Customer cust : customerList){
if(cust.getEntryId > 3){
cust.setTakeStatus(1);
update(cust);
Sd sd = new Sd();
sd.setUser(currentUser);
sd.setCust(cust);
sd.setTakeTime(new Date());
sdDao.save(sd);
}
}
}
If two user take order at the same time , the customerList maybe have same records, then duplicate record will be insert into table SD ,and the customer record will be update twice!
How to avoid this ?
use a primary key in your mysql.
create table tablename(
yourPrimaryKey int(10),
otherColumns varchar(10),
primary key(yourPrimaryKey)
);
primary key will be your unique code for every transaction. just like receipt number in any convenient store
(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 getting this exception about commits and rollbacks but am not sure what exactly is wrong with my Stored Procedure. I have read the answers in other such questions and am unable to find where exactly the commit count is getting messed up.
So, this is the Stored Procedure I use:
-- this is a procedure used for the purge utility. This procedure uses the parameters of a date and lets user select
-- if the leads that should be purge must be closed either before, on or since that date.
-- operator: 0-->less 1-->equal 2-->greater
-- #closed: closing date
-- leadscount: returns the count of leads deleted
IF OBJECT_ID ('LEAD_PURGE', 'P') IS NOT NULL
DROP PROCEDURE LEAD_PURGE
go
CREATE PROCEDURE LEAD_PURGE
#purgextns INT,
#leadscount INT OUTPUT
AS
BEGIN
BEGIN TRANSACTION
CREATE TABLE #ASSIGNMENTS_DELETED
(
ID NUMERIC(19, 0)
PRIMARY KEY (ID)
)
CREATE TABLE #MAPRESULTS_DELETED
(
ID NUMERIC(19, 0)
PRIMARY KEY (ID)
)
CREATE TABLE #COMMAND_DELETED
(
ID NUMERIC(19, 0)
PRIMARY KEY (ID)
)
CREATE TABLE #PROGRESS_STATUS_DELETED
(
ID NUMERIC(19, 0)
PRIMARY KEY (ID)
)
CREATE TABLE #DETAILS_DELETED
(
ID NUMERIC(19, 0)
PRIMARY KEY (ID)
)
CREATE TABLE #NEEDS_DELETED
(
ID NUMERIC(19, 0)
PRIMARY KEY (ID)
)
insert into #ASSIGNMENTS_DELETED
select SEQID FROM ASSIGNMENT WHERE LEADSEQ IN (SELECT ID FROM PURGE_LEAD);
SELECT #leadscount = (SELECT COUNT(*) FROM PURGE_LEAD);
INSERT INTO #MAPRESULTS_DELETED
SELECT ID FROM MAPRESULT WHERE ASSIGNMENTSEQ IN (SELECT ID FROM #ASSIGNMENTS_DELETED)
INSERT INTO #COMMAND_DELETED
SELECT ID FROM EXECUTERULECOMMAND WHERE MAPRESULTID IN (SELECT ID FROM #MAPRESULTS_DELETED)
INSERT INTO #PROGRESS_STATUS_DELETED
SELECT PROGRESS_STATUS_ID FROM COMMAND WHERE ID IN (SELECT ID FROM #COMMAND_DELETED)
INSERT INTO #DETAILS_DELETED
SELECT DETAILID FROM LEAD WHERE SEQID IN (SELECT ID FROM PURGE_LEAD)
INSERT INTO #NEEDS_DELETED
SELECT NEEDSID FROM LEAD WHERE SEQID IN (SELECT ID FROM PURGE_LEAD)
DELETE FROM PROGRESS_STATUS WHERE ID IN (SELECT ID FROM #PROGRESS_STATUS_DELETED)
DELETE FROM EXECUTERULECOMMAND WHERE ID IN (SELECT ID FROM #COMMAND_DELETED)
DELETE FROM COMMAND WHERE ID IN (SELECT ID FROM #COMMAND_DELETED)
DELETE FROM SIMPLECONDITIONAL WHERE RESULT IN (SELECT ID FROM #MAPRESULTS_DELETED)
DELETE FROM MAPPREDICATE WHERE ROWBP IN (SELECT ID FROM MAPROW WHERE RESULT IN (SELECT ID FROM #MAPRESULTS_DELETED))
DELETE FROM MAPROW WHERE RESULT IN (SELECT ID FROM #MAPRESULTS_DELETED)
DELETE FROM MAPRESULT WHERE ID IN (SELECT ID FROM #MAPRESULTS_DELETED)
DELETE FROM ASSIGNMENTATTACHMENTS WHERE ASSIGNMENTSEQ IN (SELECT ID FROM #ASSIGNMENTS_DELETED)
DELETE FROM LEADOBSERVER WHERE ASSIGNSEQ IN (SELECT ID FROM #ASSIGNMENTS_DELETED)
DELETE FROM MAPDESTINATIONS WHERE SUGGESTEDASSIGNID IN
(SELECT ID FROM SUGGESTEDASSIGNMENT WHERE ASSIGNMENT_SEQID IN (SELECT ID FROM #ASSIGNMENTS_DELETED))
DELETE FROM SUGGESTEDASSIGNMENT WHERE ASSIGNMENT_SEQID IN (SELECT ID FROM #ASSIGNMENTS_DELETED)
DELETE FROM PRODUCTINTEREST WHERE LEADSEQ IN (SELECT ID FROM PURGE_LEAD)
CREATE TABLE #SALE_DELETED_EX
(
ID NUMERIC(19, 0)
PRIMARY KEY (ID)
)
INSERT into #SALE_DELETED_EX SELECT SALEEXSEQ FROM SALE WHERE SEQID IN (SELECT SALEID FROM LEADSALES WHERE LEADID IN (SELECT ID FROM PURGE_LEAD))
DELETE FROM SALE WHERE SEQID IN (SELECT SALEID FROM LEADSALES WHERE LEADID IN (SELECT ID FROM PURGE_LEAD))
DELETE FROM SALEEXTENSIONS WHERE
SEQID IN (SELECT ID FROM #SALE_DELETED_EX)
DELETE FROM LEADSALES WHERE LEADID IN (SELECT ID FROM PURGE_LEAD)
DELETE FROM NOTES WHERE OBJECTID IN (SELECT ID FROM #NEEDS_DELETED) OR OBJECTID IN (SELECT ID FROM #DETAILS_DELETED)
DELETE FROM HISTORYRECORD WHERE OBJECTID IN (SELECT ID FROM #DETAILS_DELETED)
DELETE FROM DETAIL WHERE SEQID IN (SELECT ID FROM #NEEDS_DELETED UNION SELECT ID FROM #DETAILS_DELETED)
DELETE FROM MESSAGES WHERE PROVIDERID IN (SELECT ID FROM PURGE_LEAD)
DELETE FROM ASSIGNMENT WHERE LEADSEQ IN (SELECT ID FROM PURGE_LEAD)
DELETE FROM LEAD WHERE SEQID IN (SELECT ID FROM PURGE_LEAD)
CREATE TABLE #PURGE_LEAD_E
(
ID NUMERIC(19, 0)
PRIMARY KEY (ID)
)
INSERT into #PURGE_LEAD_E Select SEQID FROM LEADEXTENSIONS WHERE
SEQID NOT IN (SELECT LEADEXSEQ FROM LEAD)
if #purgextns = 1 begin
DELETE FROM LEADEXTENSIONS WHERE
SEQID IN (SELECT ID FROM PURGE_LEAD_E)
end
DELETE FROM PURGE_LEAD;
DROP TABLE #ASSIGNMENTS_DELETED
DROP TABLE #MAPRESULTS_DELETED
DROP TABLE #COMMAND_DELETED
DROP TABLE #PROGRESS_STATUS_DELETED
DROP TABLE #DETAILS_DELETED
DROP TABLE #NEEDS_DELETED
DROP TABLE #PURGE_LEAD_E
DROP TABLE #SALE_DELETED_EX
COMMIT
END
go
now I call this procedure in the following code:
try {
c = new ConnectionHelper().getConnection();
String sql = "";
if (shouldPurgeExtns) {
progressModel.makeProgress("progress.deleting.dependents");
purgeMultiselect(c, LEAD, isMSSQL);
}
sql = "{CALL " + TOPLinkManager.getSchemaPrefix()
+ "LEAD_PURGE (?,?)}";
cs = c.prepareCall(sql);
cs.setInt(1, shouldPurgeExtns ? 0 : 1);
cs.registerOutParameter(2, java.sql.Types.INTEGER);
cs.executeUpdate();
int rowcount = cs.getInt(2);
cs.close();
progressModel.makeProgress("progress.recording.history");
recordHistory(c, isMSSQL, LEAD, DateTypeDecorator.CLOSED, date,
rowcount);
done(progressModel);
c.close();
return true;
} catch (Exception e) {
Logs.main.error("Error Purging Leads", e);
throw new Exception(e.getMessage());
}
And I get an exception on the line which say int rowcount = cs.getInt(2);
The Exception is:
com.microsoft.sqlserver.jdbc.SQLServerException: Transaction count after EXECUTE indicates a mismatching number of BEGIN and COMMIT statements. Previous count = 0, current count = 1.
at com.microsoft.sqlserver.jdbc.SQLServerException.makeFromDatabaseError(SQLServerException.java:196)
at com.microsoft.sqlserver.jdbc.SQLServerStatement.getNextResult(SQLServerStatement.java:1454)
at com.microsoft.sqlserver.jdbc.SQLServerStatement.processResults(SQLServerStatement.java:1083)
at com.microsoft.sqlserver.jdbc.SQLServerCallableStatement.getOutParameter(SQLServerCallableStatement.java:112)
at com.microsoft.sqlserver.jdbc.SQLServerCallableStatement.getterGetParam(SQLServerCallableStatement.java:387)
Please help me out.
at com.microsoft.sqlserver.jdbc.SQLServerCallableStatement.getValue(SQLServerCallableStatement.java:393)
at com.microsoft.sqlserver.jdbc.SQLServerCallableStatement.getInt(SQLServerCallableStatement.java:437)
at marketsoft.tools.purge.PurgeUtils.PurgeLeads(PurgeUtils.java:283)
EDIT:
as I have answered this question myself... I would like to change the question a bit now.
Why was no exception thrown in the execute method???
Your COMMIT is not being hit, probably because of an error. The transaction won't be rolled back automatically
The best way (and best practice) is to add some SQL error handling
CREATE PROCEDURE LEAD_PURGE
#purgextns INT,
#leadscount INT OUTPUT
AS
SET NOCOUNT, XACT_ABORT ON;
BEGIN TRY
BEGIN TRANSACTION
CREATE TABLE #ASSIGNMENTS_DELETED
(
ID NUMERIC(19, 0)
PRIMARY KEY (ID)
)
...
DROP TABLE #SALE_DELETED_EX
COMMIT TRANSACTION
END TRY
BEGIN CATCH
IF XACT_STATE() <> 0
ROLLBACK TRANSACTION
RAISERROR ('it broke', 16, 1)
END CATCH
go
For more details on what is going on here, see my answer here Nested stored procedures containing TRY CATCH ROLLBACK pattern?
Note: you don't need to drop the temp tables as they go out of scope when the stored procedure exits
Try to add in the beginning of procedure
SET XACT_ABORT ON
Or
Wrap your statements with
begin try
BEGIN TRANSACTION
Your TSQL code
COMMIT
end try
begin catch
ROLLBACK
RAISERROR('Gotcha!', 16, 1)
end catch
To check how many uncommitted BEGIN TRAN is opened test the ##TRANCOUNT system variable
This normally happens when the transaction is started and either it is not committed or it is not rollback.
In case the error comes in your stored procedure, this can lock the database tables because transaction is not completed due to some runtime errors in the absence of exception handling
You can use Exception handling like below. SET XACT_ABORT
SET XACT_ABORT ON
SET NoCount ON
Begin Try
BEGIN TRANSACTION
//Insert ,update queries
COMMIT
End Try
Begin Catch
ROLLBACK
End Catch
Sorry Guys! Thanks for all your efforts, In the end, it was a very small mistake on my part in the Stored Procedure:
Look at line:
if #purgextns = 1 begin
DELETE FROM LEADEXTENSIONS WHERE
SEQID IN (SELECT ID FROM PURGE_LEAD_E)
end
It should be #PURGE_LEAD_E
All your answers helped me get a different perspective of store procedure development. Thanks a lot!
How exactly the #leadscount variable contains the count of leads deleted?
This is the only place I see it beeing used:
SELECT #leadscount = (SELECT COUNT(*) FROM PURGE_LEAD);
Anyhow, to test it, why don't you run the above code outside the context of the transaction?
If you really need it to be inside a transaction, try loading the value into a table variable (create a table with only one column). Since they don't participate in transactions you can test if the transaction is your real problem.