Cascade a value in a table - php

Lets say I have two tables, 'a' and 'b'. The relationship of 'a' to 'b' is one to many. Lets both tables have the field status. This field has the values 'active' and 'inactive'. If I set the field status to 'inactive', does MySQL have a way to cascade this down to all tables tied to the row I changed the status value for? Or would this have to be done at the program level?
Let me know if this isn't clear.

You could use a trigger on the parent table that updates all children as necessary. Otherwise you'll have to handle it at the same level of your application where you update the parent row.

I've never tried this, and I'm not sure if I would recommend it, but if you add the status column to your foreign key (so you have two columns: the primary key of table 'a' and status) and then use on update cascade that might work as well.

Related

Best way to modify site to allow anonymous comments

Now I have one table "comments" with 'user_id' column as foreign key. This column have a constraint - ON UPDATE CASCADE, ON DELETE CASCADE.
First (bad) way is to remove constraints for 'user_id' column. In that case we loosing connection with 'users' table, but all code stay same.
Second (also not good) way is to create one more table 'anonymous_comments'. New model, new observers, new chapter in admin panel, need to modify code in many places... many work & doubles.
Any better ideas?
If you don't want (or can't for some reason) to do any DB and code modifications, you could create a dummy user 'anonymous' and use it's user_id for anonymous comments.

Add a relation between table in PHPMyadmin

I want create a relation between different tables in phymyadmin with mysql.
I want to add cascade option but I don't always see the cascade option every time I add relation.
For example in first image when I relate usergroupid id in usergroup and users table there is not cascade option available. But as in second image when i relate invoice id in invoicedetails and tripmaster table I gets the cascade options availabale.
So I'm no able to understand why cascade option is not available every time.
There are several conditions that your tables and columns need to meet in order to create foreign key constraints.
One that you are missing in your example and that is visible from the screenshot, is the length of the integer value. They both need to have the same length (and sign...) so int(5) and int(11) are not compatible.
You also need indices on the columns, etc. see the manual on foreign key constraints for all requirements.
When you build relationships like this, the key and its matching foreign key must have exactly the same datatype.
So in your first example, the integers are of different sizes (int(5) and int(11) thus MySql cannot create the required constraints and you cannot enable cascade deletes or updates.
In your second example, its not clear from the screenshot but I assume that the datatypes match.
Also ensure that integer datatypes are both signed or unsigned. If one is signed and the other unsigned, you'll run into the same problem.

How to handle cyclic foreign key insertion?

I have a table 'release_group' and another table 'release', like so:
release_group
------------------------
release_group_id (PRIMARY KEY)
name
main_release_id (FOREIGN KEY)
release
------------------------
release_id (PRIMARY KEY)
release_group_id (FOREIGN KEY)
name
If i create a release row, the release_group_id is not available, simply because it hasn't been created yet. But i can't create a release_group row without the main_release_id. So it's kind of a no way situation.
EDIT:
The main_release_id in release_group is to say that the release is the main from the group, the one i will use a reference.
What is the professional way of handling this case?
1.
Remove the foreign key index main_release_id in table release_group and give an attribute ALLOW NULL. Create the release_group row so i can applied it's id in the release row.
2.
Keep the 'main_release_id' foreign key index in table 'release_group' and assign it a temporary integer value of 0. Create the release row and update the foreign key in the release_group accordingly? Keep in mind that if this is the way to go, i could end up inadvertently having foreign keys with value 0, which i don't know if this ethic in a database?
What is the professional way of handling this case?
Thanks
Seeing how a release cannot belong to more than one group, you could remove the complication by:
Dropping the main_release_id field altogether
Add a release_main field to the release table; it would be NULL (not main) or 1 (main).
Add a UNIQUE constraint on (release_group_id, release_main) to make sure there can only be one main release.
Update
If a release can belong to multiple groups, you would need to create a many-to-many table and move the foreign key in both tables into it:
(release_group_id [FK], release_id [FK], is_main)
The primary key would span the first two fields. Ensuring that there can only be one main release requires a spanning unique key over the first and last field.
Old answer
Assuming main_release_id is a nullable field, what I would suggest is the following:
Insert the release_group with main_release_id being null; get last inserted id.
Insert the release entry, passing the id of the previous step; get last inserted id.
Update the release_group table entry, setting the value of main_release_id to the value you got from the previous step.
Commit transaction
Alternatively, you could use sequences so that you know the id before inserting the entries. See an example of this in the manual under LAST_INSERT_ID().
Looks like you are trying to create a many to many relationship. To do this properly, remove the foreign keys from both the release_group and release tables. Add a new table (release_to_release_group) that contains the release_id foreign key and the release foreign key.
Edit: There is no need for cyclic foreign keys here. Remove the main_release_id foreign_key from release_group and add a is_main_release flag to the release table.
It's not usual practice to have the tables reference each other like that. Usually you would have the Parent table (release_group) as a foreign key reference in the child table (release), but not have the release_id as a foreign key in the release_group table.
Maybe add a boolean flag to the release table to indicate it is the Main release and do away with the main_release_id in release_group.

PHP update MYSQL many-to-many relation

I have a many-to-many relation, implemented with an association table in MySQL. I have a table for children and a table for parents. A child can have multiple parents, saved in the parent_child_link association table with their ID's.
Children can be updated through a HTML form, the parents are in a HTML multi-select. Now I need to update the record in the database, but my solution is not very efficient. Here's in pseudocode what I do:
Update the child information where child_id=x
Delete all the current associations in parent_child_link where child_id=x
Insert the new associations
This solution works great, but when the the parents weren't changed, e.g. only the name of the child was changed, then there are 2 unnecessary queries executed. How can I avoid those unnecessary queries? Is there some way to check if the parents in the multi-select didn't change?
Ofcourse I could just ignore all this hassle, because it already works, but I really like to keep things as efficient as possible.
I have the same question and figured out my solution as I was reading.
When I am ready to process the submitted entries, I first do a query to get the current associations and call that array $original_list. The submitted list I will call $submitted_list.
$original_list = array(3,5,7);
$submitted_list = array(1,2,3);
Then I just need to figure out 1) which items to delete (no longer exist) and 2) which items to add (new associations). Items in both lists do not get touched.
$delete_list = array_diff($original_list, $submitted_list);
$insert_list = array_diff($submitted_list, $original_list);
foreach($delete_list as $item) {
// delete $item from DB
}
foreach($insert_list as $item) {
// insert item in db
}
Would love to know if others feel this a valid solution.
Try solving it in the database, not in the application layer by using ON UPDATE CASCADE and ON DELETE CASCADE in the definition of the child table.
A slightly revised example form the MySQL site:
CREATE TABLE parent (id INT NOT NULL,
PRIMARY KEY (id)
) ENGINE=INNODB;
CREATE TABLE child (id INT, parent_id INT,
INDEX par_ind (parent_id),
FOREIGN KEY (parent_id) REFERENCES parent(id)
ON DELETE CASCADE ON UPDATE CASCADE
) ENGINE=INNODB;
Check out the docs here: http://dev.mysql.com/doc/refman/5.5/en/innodb-foreign-key-constraints.html
EDIT: For your many-to-many relation you can use something like:
CREATE TABLE parent_child_link (
parent_id INT NOT NULL,
child_id INT NOT NULL,
PRIMARY KEY(parent_id, child_id),
FOREIGN KEY (parent_id) REFERENCES parent(id)
ON DELETE CASCADE ON UPDATE CASCADE,
FOREIGN KEY (child_id) REFERENCES child(id)
ON DELETE CASCADE ON UPDATE CASCADE
);
Hope this helps.
Your solution is fine.
In your case you could "optimize" the process by making a query to retrieve the parents and check with the multi-select data if any changes has occurred.
Then you only perform the two delete and insert queries if needed. The counterpart is that when you actually changed the parents, then there will be 3 queries instead of 2.
So you should ask you if the you are about to modify the parents very often. In this case you should stick to your original solution to avoid an extra select query.
If you think the parents won't be updated very often, then you can go with the above solution. When you update the child info only, only one query is performed. When you also update the parents, 3 queries are performed.
When you go with the second solution, the delete and insert queries can be optimized too to only perform what is required (only delete the parents that are not his parents anymore and only insert new parent links).
PHP array functions can be helpful for that.
If you want to keep you'r current way of doing it, but just optimizing, you could wrap the queries in IF statements.
Like:
if ( isset ( $parent_name_change )){
// run query
}

Problem with auto-incremented "id" column

My db table looks like this pic. http://prntscr.com/22z1n
Recently I've created delete.php page. it works properly but when i deleted 21th user next registered user gets 24th id instead of 21.
Is it possible to put newly registered users info to first empty row? (In this situation 21th row)
In my registration form, newly registering user can write names of existing users, and be friends with them after registration. For this friendship i have another table that associates id of newly registered user and existing user.
For this purpose i'm using mysql_insert_id during registration to get id for new user. But after deletion of 21th row during nex registration process mysql_insert_id gave me number 21. but stored in 24th row. And put to associations table 21 for new user. I wanna solve this problem
When you use an autoincrement id column, the value that the next entry will be assigned will not be reduced by deleting an entry. That is not what an autoincrement column is used for. The database engine will always increment that number on a new insert and never decrement that number on a delete.
A MySQL auto_increment column maintains a number internally, and will always increment it, even after deletions. If you need to fill in an empty space, you have to handle it yourself in PHP, rather than use the auto_increment keyword in the table definition.
Rolling back to fill in empty row ids can cause all sorts of difficulty if you have foreign key relationships to maintain, and it really isn't advised.
The auto_increment can be reset using a SQL statement, but this is not advised because it will cause duplicate key errors.
-- Doing this will cause problems!
ALTER table AUTO_INCREMENT=12345;
EDIT
To enforce your foreign key relationships as described in the comments, you should add to your table definition:
FOREIGN KEY (friendid) REFERENCES registration_table (id) ON DELETE SET NULL;
Fill in the correct table and column names. Now, when a user is deleted from the registration, their friend association is nulled. If you need to reassociate with a different user, that has to be handled with PHP. mysql_insert_id() is no longer helpful.
If you need to find the highest numbered id still in the database after deletion to associate with friends, use the following.
SELECT MAX(id) FROM registration_table;
Auto increment is a sequence key that's tracked as part of the table. It does not go back when you delete a row.
Easily, no. What you can do (but I don't suggest doing) is making an SQL function to determine the lowest number that isn't currently occupied. Or you can create a table of IDs that were deleted, and get the smallest number from there. Or, and this is the best idea, ignore the gaps and realize the database is fine.
What you want to do is achievable by adding an extra column to your table called something like user_order. You can then write code to manage inserts and deletions so that this column is always sequential with no gaps.
This way you avoid the problems you could have messing around with an auto_increment column.
It's not a good practice to reset auto_increment value, but if you really need to do it, so you can:
ALTER TABLE mytable AUTO_INCREMENT = 1;
Run this query after every delete. Auto_increment value will not be set to 1, this will set the lowest possible value automatically.

Categories