How to handle cyclic foreign key insertion? - php

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.

Related

phpmyadmin replacing table

Can I replace a table in DB through phpmyadmin. Table has two foreign keys and I can truncate it by disabling foreign key checks (or delete it completely), however when I try to reupload it, if I don't enable foreign key checks it doesn't connect to the tables it should (I can't click on foreign ID, usually it takes me to the related table). If I do enable foreign key checks I get an error
#1452 - Cannot add or update a child row: a foreign key constraint fails
Is there a way to somehow replace a table with the same table from the past by keeping the relations alive?
i think the table contains data ... try clearing the table before dropping it.
Actually "you don't need to disable foreign key checks" if you want to delete from (or truncate) only the table(s) where child records are stored. You should be able to delete all and re-insert them later. Please try it this way.
You need to disable the foreign key checks if you want to truncate the tables with primary keys without deleting the child records. (This is not reasonable though.)
The following steps in order should work fine without disabling any constraint. If you don't follow the order, it will fail. You can skip the steps 2 and 3 and use 1 and 4 only.
Delete all child records with foreign key pointing to a primary key.
Delete all master records with primary key.
Re-insert all master records with primary key.
Re-insert all child records with foreign key pointing to a primary key.
Anyway, the error you get sounds like when you try to insert the old data, the matching record is missing in the master table where the foreign key points to.
You can check:
Whether the data in the master tables (the tables with primary key where foreign keys point to) are also deleted or truncated. If so, you need to bring them back before the child records.
Whether the data in the master tables are not the same anymore and the consistency is lost with the old data. (If you are working on a production database, the data might be changing). If so, you need you need to bring the missing records back to the master table.

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.

PhpMyAdmin foreign key constraint not functioning

I have watched several tutorials on setting up foreign key constraints on phpMyAdmin now, but I can never seem to make it work.
My aim is to store names in the names table, then have those names as the foreign key of the stats table, where the stats linked with each player will be stored.
The stats table (with index)
(The name table is indexed in the same way as the stats, using the index button)
The setup of the foreign key constraint
No connection seems to have been properly made, since attempting to display the values of statname in PHP yields nothing.
I realise that it's important for the concerning fields to have IDs, which I have created, and in the version of phpMyAdmin I have (4.5.1), ID names don't seem to be displayed in the foreign key constraints section, only the fields those IDs refer to.
I'm pretty new to this, any help and advice would be welcome.
In the player names table, make a field (player_id) which stores the unique id of each player as the primary key which will uniquely identify the player from the table.
Next, in your stats table, take a field (player_id) amd make it as a foreign key which will reference the (player_id) field from the player table to refer the player stats in the stats table.

Doctrine with one field of the composite primary key to be auto generated

I currently have a table that has as primary key a composite value formed by id + foreign key. The id is auto-incremented and the foreign key references another table.
At the moment that I'm saving the data I only know about the foreign key value and I expect that the id returns to me from the database as an auto-increment number.
I understand that doctrine's does not support auto generation of id for a composite primary key so what can be done to allow with Doctrine to save the data and still have the auto-increment on part of the composite key.
Note, before submiting this question I had researched several other questions such as: Defining Composite Key with Auto Increment in MySQL and Doctrine: authorize NULL in a foreign composite key and I have also read Doctrine's documentation several times to see if I was missing something http://doctrine-orm.readthedocs.org/en/latest/tutorials/composite-primary-keys.html#use-case-1-dynamic-attributes
The main issue is that on Doctrine
Every entity with a composite key cannot use an id generator other than
“ASSIGNED”. That means the ID fields have to have their values set before
you call EntityManager#persist($entity).
To help with the issue here is an example of how the table is constructed:
create table composite_example (
id int(11) not null auto_increment,
fk_id int(11) not null,
a_prop varchar(20),
primary key (id, fk_id)
) engine=InnoDB default charset=utf8;
If I had to manually construct a MySQL query to insert into this table knowing the values of fk_id and a_prop I could do:
insert into composite_example (fk_id, a_prop) values (999, 'a_value');
And it would create a row with a proper value for id on the table.
How can I do the same behavior with Doctrine ? Does anyone knows any way or workaround to get the job done ?
There is no easy solution for this matter but here are a few options:
1) You can remove composite key and use UUIDs as keys. This is not an easy solution because it will affect how much of your code needs to be changed, how long it will take to do the migration and how it can affect performance.
2) The other option would be something that was suggested by the Doctrine community that can be used in other ORM's as well: you work with a sequencer. For this solution you will need to create a table where you will store an entity identifier and the next column will be the last value for that identifier.
Example:
Table sequencer
id | entity_name | entity_id
88 | customers | 77
The entity model would need to inform that the id is generated and on the pre-persist it will need to assign that id with a value that would come from the entity_id + 1 out of this table
select max(entity_id)+1 from sequencer where entity_name = 'customers';
This will cause 2 extra queries to be ran, one on the pre-persist and another on the post-persist which will update the sequencer table with the new value.
There are strategies to avoid concurrency on the sequencer table so it would always have the correct value and one of them is by locking the table o.0
3) You can write your own loaders and persister, but at this point you might be facing a change as big as the UUID implementation.
A lot of ORM's doesn't support this and if you are facing the same issue, you might have to consider one of the above.
Now, if you are working specifically with Doctrine I strongly suggest asking for help on the IRC channel. They were very helpful on providing me with some alternatives for this issue.

Should I index my mysql foregin keys

I am using mysql as DB for my Laravel app.
In one table I have 5 fields that are foregin keys, those FK's points to 5 other tables primary keys.
Right now I have only marked them as FK, but do I need to put a index on every FK as well? Or does a FK count as a index?
Thanks in advance,
In mysql when making a FK it automatically indexes that column(s).
MySQL requires indexes on foreign keys and referenced keys so that foreign key checks can be fast and not require a table scan. In the referencing table, there must be an index where the foreign key columns are listed as the first columns in the same order. Such an index is created on the referencing table automatically if it does not exist. This index might be silently dropped later, if you create another index that can be used to enforce the foreign key constraint. index_name, if given, is used as described previously.
You can read more here at dev.mysql

Categories