When I am using Foreign Keys in MySQL, I will get an error if the source value is 0 (because there is no target record with ID 0). Therefore, I am changing the source column to be NULL, and then it works. However, I am not sure if this is the right way this should be done. Is it the right way, or can I somehow keep the source ID set to 0 instead of NULL?
Foreign keys are constraints. This means that if the value of the column that has the foreign key is set to anything (and "anything" does not include NULL), that value must exist in the referenced table or MySQL will throw an error.
So, in short, you can either set the value to NULL, remove the foreign key constraint and set the value to whatever you desire, including 0, or add a record with a 0 in the referenced table. Of these options setting the value to NULL seems the cleanest.
It is the right way. 0 is a value and null says that there is nothing in the column.
Yes, this is the right way. The whole point of an FK is to enforce that a record with the referenced ID actually exists. So if you set the FK column to 0, there must be a record with ID 0.
The only way around this is to make the FK column NULLable, as you did.
At any rate, why would you want to set the FK column to 0? The canonical value for "does not exist" in SQL is NULL.
using a NULL is better than zero for two reasons. first, it's clearer that it's a "special" value (there's nothing that forces table ids to always be non-zero, although it is often true for auto-generated ids), and second it works in SQL with the foreign key constraint.
so what you are doing is common practice - many people use NULL as a marker that says "missing value", and that's what SQL's foreign key constraint expects.
another way to handle missing values is to use a third "link" table that has an entry only if there is a connection between the two classes (as you would do in a many-to-many relation). this avoids the need for a NULL, and so is preferred by some database purists, but makes everything more complex. see Nullable Foreign Key bad practice? for more discussion.
Yes, this is the right way and the correct pattern to use in those cases.
As stated, what is indicated in those structures is to leave the column as null, indicating the line would not be linked to any counterpart in the foreign table. It whould not be considered "right" in database teories, but is a very used pattern, so, its not actualy considered "wrong" by the most of database designers. I gues you could say its the kind of pattern you try not to look to when trying to find mistakes in the structure.
The pattern is considered incorrect because it is expected to use a non-null column in a primary key and in this sense the columns in the table that will receive the key must be identical to the primary column of the table, that is, they would never be null. However, in most databases physically, there are no impediments to creating a different column, which makes the null value possible.
The problem with this architecture is when the table gets too big, when, p. eg, it have more than 1000 lines (yes, the "big" would be that low!), in these situations, specially in a small infrastructure, the answer time starts to get too long and "questionable". It happens that null records can not be part of indexes and the algorithm ends up doing a full scan. Therefor this type of pattern is implemented when we know the table will always be verry, verry small! Otherwise, I recommend use the pattern creating an external table where the "null" option in your case would be a "not found" in this other table.
Related
I want to structure a MySQL table with many of the the usual columns such as index as an integer, name as a varchar, etc. The thing about this table is I want to include a column that has an unknown number of entries. I think the best way to do this (if possible) is to make one of the columns an array that can be changed as any entry in a database can. Supposing when the record is created it has 0 entries. Then later, I want to add 1 or more. Maybe sometime later still, I might want to remove 1 or more of these entries.
I know I could create the table with individual columns for each of these additions, but I may want as many as a hundred or more for one record. This seems very inefficient and very difficult to maintain. So the bottom-line question is can a column be defined as a dynamic array? If so, how? How can things be selectively added to or removed from it?
I'll take a stab in the dark and guess maybe make a table contain another table. I've never heard of this because my experience with MySQL has been mostly casual. I make databases and dynamic websites because I want to.
The way to do this in a relational database is to create another table. One column of that table will have a foreign key pointing to the primary key of that table that should have had the array (or multiple columns, if the primary key consists of more than one row). Another column has the values that'd be found in the array. If order matters, a third column would store some other values indicating the ordinality.
Something along the lines of:
CREATE TABLE elbat_array
(id integer,
elbat integer -- or whatever type the primary key column has
NOT NULL,
value text, -- or whatever type the values should have
ordinality integer
NOT NULL, -- optional
PRIMARY KEY (id),
FOREIGN KEY (elbat)
REFERENCES elbat -- the other table
(id) -- and its primary key column
ON DELETE CASCADE,
UNIQUE (ordinality));
To add to the "array", insert rows into that table. To remove, delete rows. There can be as many as zero rows (i.e. "array" elements) or as much as there's disk space (unless you hit any limit of the DBMS before, but if such a limit applies it would be very large, so usually that should not be a problem).
Also worth a read in that context: "Is storing a delimited list in a database column really that bad?" While it's not about an array type in particular, on the meta level it discusses why the values in a column should be atomic. An array would violate that as well as a delimited list does.
Let's say I have a table like this:
CREATE TABLE dept (
id VARCHAR(255) NOT NULL PRIMARY KEY,
code VARCHAR(255) NOT NULL,
active BIT NOT NULL,
...
);
Problem:
I want to add a unique constraint on code column. But it should be applied only if active is set to true (uniqueness should be checked only among active records). There can be many records with active = false and the same code so I can't use constraint on multiple columns.
What I tried:
I haven't found any references in the documentation proving that such constraint is possible, but I know it is possible in other databases using unique function-based indexes.
Of course I can write a trigger that will check the invariant on every add/update operation, but I hope there is more efficient solution.
I'm using MySQL 5.7.15.
This simply isn't possible in MySQL, I'm afraid.
I have come "close" to solving this in the past by having a uniquely constrained column which is nullable (replacing both the active and code fields). When NULL - it's "inactive", when anything other than NULL - it has to be unique.
But that doesn't precisely solve the problem you're asking. (Perhaps something better can be suggested if you could update your question to include the bigger picture?)
Otherwise read/write to the table through a stored procedure or - as you've suggested yourself - do something inelegant with triggers.
To solve your problem you need use CHECK clause but it MySQL don't support it. From doc:
The CHECK clause is parsed but ignored by all storage engines. See Section 13.1.18, “CREATE TABLE Syntax”. The reason for accepting but ignoring syntax clauses is for compatibility, to make it easier to port code from other SQL servers, and to run applications that create tables with references.
So you can do this only by check data on application level or insert/update rows in this table by stored procedures.
I sorry this does not really a direct answer your question but:
Maybe you are better off with a different table design? The fact that something you want to do is not supported by your RDBMS is always a strong evidence that you are using it wrong.
Have you thought about creating a dept and an dept_history table, dept containing only the active records? That would solve your problem with the unique constraint.
I know this is an odd question because I've always been taught to use a foreign key constraint. However, I've come across a case where a foreign key reference value must be kept for historic purpose when the reference is deleted.
It is a task management system whereby a task occurrence references a parent task containing the recurrence rule. This parent task can be deleted, but the occurrence itself must remain in tact with the non-existing parent id. If the parent task cannot be found, the system simply returns an error - eg "parent task no longer exist." The reason why the parent id cannot be set to null on cascade is because it is being used elsewhere in the occurrence as an identifying key.
Another example: What about a YouTube video that was removed from a playlist. Similar situation right? It is being referenced in the playlist, but the video doesn't exist, so it returns an error in the playlist instead.
Do I simply not define a foreign key at all and just simply create the parent_id reference column as a normal column? I just want to be sure how this is normally handled when one encounters a case where one table references another, but the former is not constraint by the existence of the latter.
Having a constraint is just a technical helper to enforce the semantics defined for the database, i.e. "this column contains a number that is not only an INTEGER(32) but also an identifier for a record in some other table". As such they're not strictly necessary, but it:
makes the intention of the field clear (self documentation)
keeps your data "clean" by preventing incorrect data from being inserted
gives the database engine a hint concerning the content of the table which may allow the db to perform more efficiently.
That said, the "proper" way to accomplish what you've described would be not to physically delete the parent record in the first place. Instead, mark the parent as deleted. Since you're keeping the record for historical purposes, surely you'll want to be able to know what the parent used to be, even if it's no longer active or valid.
Second option would be to create a dummy "parent record deleted" reference. Whenever you delete a parent, you update remaining references to point to the dummy record instead. At least you wouldn't rely on errors to implement expected and valid behaviour.
Finally, I see no reason you shouldn't be able to set the foreign key to NULL. It sounds like you're using the foreign key as part of the primary key of the record in question ("is being used .. as an identifying key"). This you almost certainly should not be doing, if that's the root cause of the problem, start by changing that.
Do I simply not define a foreign key at all and just simply create the
parent_id reference column as a normal column?
Yes. At least this is the way I got to know and how we handle this stuff at work.
You might then want to set an index on the reference column.
How to rearrange primary key column values after deleting some rows from a table in MySQL?
Foe example; a table with 4 row of data with primary key values 1,2,3,4. When delete 2nd and 3rd rows, then the key value of 4th row change to 2.
Please help me to find solution.
Why do this? You don't need to rearrange your key since it's only number, identifier for record. It has no actual meaning - so let DBMS handle that. This is a very common mistake - trying to take DBMS role.
However, I'll answer your question for common case. In MySQL you can rearrange column with:
update t cross join (select #cur:=0) as init set t.col=#cur:=#cur+1
-this, however, can't be used with column under UNIQUE (so primary key as well) restriction since during update you'll possibly get duplicate records. You should drop restriction first before do that (and create it again after update).
One method is THIS ONE.
Other then that, you can simply drop the table which is primary and then again create it. This will do the job
Why do you want to change primary keys for your data? In general this is bad idea to do that, especially when integrity contstraints comes into the game. If you need to do such thing, I would say you have bad DB desing and you should take closer look on that aspect.
I am generating a data template in C#. With the help of the good people on this wonderful site, I've managed to take care of almost every issue. This should be the last problem. Because it's a template I'm working on, I want every field in the table, including nulls. I was helped on how to update nulls by adding (object)this.field ?? DBNull.Value but I have a field that's a foreign key and even though when I look in the database it says null, when I pull the records the value becomes 0. When I try to update this field it says that I am violating foreign key constraints. How can I work around this problem? I thought the null solution would work but it doesn't show as null, it shows as 0.
Thanks
Is 0 a possible valid value for the column? If not, just typecast it to null when you encounter one. If it is valid you can still do that, by wrapping it in a conditional that checks the foreign row exists first.
In general it's not a good idea to allow FKs to be null. Some databases (I know oracle does this) enforce this by tying FKs to primary keys rather than columns in other tables. Could you refactor your tables not to need nulls for that column?