Deleting an Entry in the join table of a Many-to-Many Relationship - many-to-many

Using the example in the documentation: I have Doctors and Patients who are connected over a join table.
Now I delete a Patient from a Doctor, which works fine, i.e. the row in the join table vanishes:
doctor.remove(patient);
Is there a way that I can retrieve the remaining (n-1) patients without having to reload the Doctor from database, i.e.
doctor.getAll(Patient.class);
When doing this without reloading the Doctor I still get the just deleted entry.
Also cache purging does not work.
Only when I also reload the doctor from database the deleted entry is gone.
Is this the only way which works?

This is exactly how the framework works. This code:
doctor.remove(patient);
removes the record from the join table. After that, calls:
doctor.getAll(Patient.class);
will not be returning removed patient. I tested this by writing additional test method in the https://github.com/javalite/activejdbc/blob/master/activejdbc/src/test/java/org/javalite/activejdbc/Many2ManyRelationshipTest.java.
Here is the test I added: https://gist.github.com/ipolevoy/821e986c5c7deb28a90d
As you can see, line 9 gets only one patient, because the other was removed on line 7.
You can turn logging on: http://javalite.io/logging to see what statements the framework is executing.

Related

Trigger updating all rows

I’m having problems with a MySQL TRIGGER.
I have an employees table with some basic information. Then I have a VIEW that we call our finance_system. The finance_system VIEW holds a lot of information from many sources. A few columns in the finance_system are related to an internal sales draw and return random values from other tables each time the finance_system VIEW is queried. Lastly, I have a table called EP1. Its job is to hold some of the data from the finance_system, particularly some of the columns with random values. This keeps them from UPDATING /Changing with every query. The EP1 table gets updated via a TRIGGER that fires AFTER AN UPDATE to certain columns within the employees table. The trigger works and the EP1 table gets updated, but it’s updating the entire table rather than the rows associated to the employee_id that was updated.
I read Stacks policy prior to posting and understand a reproducible example is necessary so I created a Fiddle, but I’ve obfuscated the data and only included a few columns. Hopefully it’s enough as I’ve exhausted Google trying to figure out why it’s not working.
https://dbfiddle.uk/?rdbms=mysql_8.0&fiddle=942dbabba180df86b7ac9317bbcdd64b
Edit:
Simpler version: When Table1.status is updated, the trigger should update Table3.rand1 with the values from Table2.rand1 where the ID’s match. Each ID has two rows in Table2 and Table3. My current problem is that when the trigger fires it updates all the rows in Table3 and I want it to only update the rows associated to the ID that was update in Table1. A join won’t work in this scenario, as Table2 is actually a VIEW using rand() in my real data.
https://dbfiddle.uk/?rdbms=mysql_8.0&fiddle=329e2dd3bf2fff39afc5388721c53ddc
Aimee
Check the trigger's UPDATE query: it is missing a WHERE clause, hence all rows of Table3 get updated instead of the ones matching the desired id.

Database Corruption: Missing/Duplicate Records in MS Access Database

The Problem
I have a VB6 application which uses Microsoft Access as the back end. The app is used in a multi-user environment. Recently, with no changes made to the application, we're seeing that in one of the tables of the database some records aren't being saved, while other records are saved twice, or some time even 3 times.
The Details
It's a VB6 application with Access 2002 as the back end. The app is installed in a computer running Windows 2008 Server. Multiple users on the network have a shortcut to the application on their computers and they run the application at once, accessing the same database but different records.
The application uses the following logic to save a record to the database:
1
If objectID > 0
' existing record
sql = "UPDATE myTable SET a=..., b=..., etc WHERE Id = objectID"
cn.Execute sql
Else
' new object; create new record
nextID = "SELECT Max(id) + 1 FROM myTable"
sql = "INSERT INTO myTable (a,b,c) VALUES (...)"
cn.Execute sql
objectID = nextID
End If
Exit Function
Err_Handler:
' handle the case where two people get the same ID
If timeNotExpired Then
' Try saving again;
Resume 1
Else
' Could not save; display error
End If
Thus when saving a record, if it exists it's UPDATED, otherwise it's INSERTED. The primary key field is obtained by calling Max(ID) + 1. With this setup, it's possible that Max(ID) + 1 may return the same ID for two users that are saving to the same table at the very same time. If this happens, the application goes back to where that label 1 is, and Max(ID) + 1 is called again until there is no conflict or until the save operation times out. Simple.
Last week, out of the blue, with no changes made to the application, it just started happening that (1) records in one table would randomly not save, or (2) a given record in that same table would show up in the database twice or even 3 times. In other words, a record in that table would appear in the database more than once.
It doesn't happen all the time but it happens a good 5-10 times a day. Please note that there are at least 5 people using the application throughout the day, mostly for data entry purposes. If a given record isn't save properly, the data gets out of sync and the application displays a message. At that point, if I check the database, I'll see that a record is either missing or duplicate. And usually, when it happens to one person, it will happen to other users who are also entering data. At the same time.
Edit
Let me add a bit more context... I have two tables (among others) that represent a parent/child relationship as in a customer/order scenario. A parent is required to have at least one child and the application has checks in place to ensure that a parent is not saved to the database unless the user has added at least one child for it. A user may not proceed to do anything with the application if he adds a parent without any children. The database code that saves parents (and children) has an if statement that reads something along the lines of "If parentHasNoChildren Exit Function". There's absolutely no way, absolutely no way, abso...lutely no... way... for the application to run code which would result in a parent that is saved to the database with no children.
But alas, starting last week, with absolutely no modifications to the application, we're seeing parents with no children left and right in the database. The problem occurs about 10 times per day, per user.
I have since modified the application so that it alerts the user when it finds a parent that has no children. If so, the program instructs them to delete the record and add it again, after which everything is fine.
Now, the fact that parents are reaching the database without children can only mean that (1) the application attempted to save the child, (2) Access returned no errors and behaved like everything was ok and (3) the application "thought everything was peachy" when in fact the child was not saved at all. And I know Access returned no error because the application logs every error that occurs during save operations. I checked the logs and there are no errors about children not being saved.
Edit 2: (I believe I found the problem!)
Upon inspection of the database, I just discovered that the primary key in the child table is gone. That is, the field that is supposed to be set as the primary key is there, but it isn't set as the primary key. I have no idea how this happened. The database design hasn't been touched so I'm assuming MS Access woke up one day and said "hmm, I wonder what would happen if I deleted the primary key from this table..."
In any event, I believe this is definitely the cause of my problem. The primary key was set up to prevent duplicate entries. With the key gone, it's possible to save two child records with the same ID. Since my code uses Max(ID) +1 to generate the ID for new child records, it's possible that Max (ID) +1 would return the same ID for multiple users that attempt to save a child record at the very same time. This would not be a issue in the past because Access would produce an error regarding the duplicate IDs and the application would detect the error and simply execute Max(ID) +1 again. But with no primary key, two child records would be saved with the same ID. And later, if any of the users made a change to one of those records, then both records would be updated and all fields for both (including the foreign key for the parent, parentID) would be set to identical values. This would then result in one parent having no children, and another parent having duplicate children. My goodness what a mess!!
I just tried adding the primary key to the table and I can't because there are duplicate records which I must find and delete. I'll post the final result as an answer after I'm able to add the primary key back. Thanks for all your help.
Now one last note: the table in question is the largest in the database, containing well over 3.5 million records. The table has 22 fields, 20 of which are long integers, one is a text field with a field size of 100. The other a Boolean field.
What I've Done
Since the application hasn't changed, I immediately assumed (and continue to assume) that the problem is corruption in the MS Access Database. I have done the following:
Compact the database every day
Create a fresh database and import the tables from the old database to the new one.
Create a new database and import only the definition of the tables, one at a time, then use Append Queries to get the data over to the new database.
Made sure I got latest service packs for Office
Made sure connection objects and recordsets are properly closed/disposed of
Contemplated suicide
Read and implemented suggestions detailed by a Microsoft article about how to keep a Jet database in top working order.
I'll also go over the application with a fine comb to see if I find anything, though everything points to Access being the culprit
Any Ideas?
Has anyone been in a situation like this before? I myself had a a similar issue with the same database about 10 years ago. Back then, I was getting the "Unrecognizable file format" error which was a clear case of database corruption. I fixed it by creating a new database and importing the tables, but that hasn't helped this time. Any ideas?
I would check the data type of the ID column, and make sure it is large enough. Consider changing it to a counter data type instead of running a domain function (MAX(ID)), or a replicationID if possible. That's where your issue may be happening.
I've set the ID to LONG before, and maintained my own counter in another table. Maybe a table that holds the NextID column, and a VBA function that gets this and updates + 1 for the next guy. Within a transaction this can be more reliable than MAX, which has to contend with locks.
Good luck!
It turns out the issue stemmed from the fact that Microsoft Access dropped the primary keys of two tables on the database. Because I use Max(ID) + 1 to obtain the ID for new records, and there are multiple users creating new records at once, the same ID was sometimes used for more than one record. This caused the issues mentioned above.
To solve the problem, I simply added the keys back after deleting any duplicate entries I found.
I'll also try to stay clear of Max(ID) + 1 for new records as suggested by #DanielG.
If anyone else is unlucky enough to be working with MS Access in a multi-user environment, I suggest following Microsoft's suggestions outlined in the article How to keep a Jet 4.0 database in top working condition.
Thank you all for your help!

Complex MySQL Delete Query

Current Structure
As you can see Path can be referenced by multiple Tables and multiple records within those tables.
Points can also be referenced by two different tables.
My Question
I would like to delete a PathType however this gets complicated as
a Path may be owned by more than one PathType so deleting the
Path without checking how many references there are to it is out
of the question.
Secondly, if this Path's only reference is the PathType I'm
trying to delete then I will want to delete this Path and any
records in PathPoints.
Lastly, if there are no other references on Point from any other records then this will also need to be deleted but only if its not used by any other object.
Attempts So Far
DELETE PathType1.*, Path.*, PathPoints.*, Point.* FROM PathType1,Path,PathPoints,Point WHERE PathType1.ID = 1 AND PathType1.PATH = Path.ID AND (SELECT COUNT(*) FROM PathType1 WHERE PathType1.PATH = Path.ID) < 1 AND (SELECT COUNT(*) FROM PathType2 WHERE PathType2.PATH = Path.ID) = 0
Obviously the above statement goes on but this isn't the right way about I don't think because if one fails then nothing is deleted...
I think that maybe it isn't possible to do what I'm attempting through one statement and I may have to iterate through each section and handle them based on the outcome. Not so efficient but I don't see any alternative at this time.
I hope this is clear. If you have any more questions or need any clarification then please do not hesitate to ask
First there is no way I would do this in a query like that even if the database allowed it which most will not. This is an unmaintanable mess.
The preferred method is to create a transaction, then delete from one table at a time starting with the bottommost child table. Then commit the transaction. And of course have error handling so the entire transaction is riolled back if one delete fails to maintain data integrity. If I intended to do this repeatedly, I would do it in a stored proc.

Inserting data in MYSQL is placed after a recently deleted record

I have designed a page using PHP, JavaScript and MYSQL, where it holds id(Auto incremented) images, names and so on. every thing works fine, i can insert, update or delete the records with click on respective buttons. what i have noticed that once a record deleted and when i try to insert a new record, it gets placed exactly after recently deleted record. for example. if i have 18 records, i delete record # 14 and insert a new record which obviously will be record # 19, it will be place after deleted record which was #14. is there anyway to force the insert to place the new record at the end of the table (after last record #19)? i don't want to get into phpMyAdmin and use Alter table order by...
when using select i have no problem as i'm using ORDER BY.. so that it displays every thing as i want.
Appreciating all your help.
Fardin
By definition, SQL tables have no natural order. Relying on the natural order that some MySQL table managers provide is going to lead to very fragile code. Please consider sticking with the SQL standard and ordering your rows on retrieval.
You cannot control how MySQL controls the recycling of deleted-record space.
Here is a comment from MySQL that says, essentially, the same thing: http://forums.mysql.com/read.php?108,41767,41836.

Check if a row could be deleted in MySQL

Is there a way I can check if a row potentially could be deleted? That it for example is not currently connected through restricted foreign keys to anything else.
Reason: I am making an admin page with all the users in the system listed. They can always be disabled, but they may also be deleted. However they can only be deleted if they are not connected to anything critical. And I would like to not having to check that manually if it can be done easily in the database.
Note: I do not want to actually delete any user. I just want to display to the admin that a user could be deleted.
You could try deleting it as part of a transaction, and then roll back the transaction if it succeeds. BUT, I guess the immediate followup question is, why wouldn't you know in the first place if you could delete the row or not?
You could use a view to sum up the number of dependencies without having to worry about storing the data & keeping it current. When the number of dependencies is zero, make the delete option available in the UI...
You can get all orphaned rows by left joining to the table they're connected to, e.g. this will give you all the user id's that don't have any jobs.
SELECT u.id FROM users u LEFT JOIN jobs j on u.id=j.user_id WHERE j.user_id is null;
Try one of the answers here.
MySQL: How to I find all tables that have foreign keys that reference particular table.column AND have values for those foreign keys?