I have a rails app with records that contain foreign IDs linking to records other records (belongs_to).
I am aware that index IDs start at 1 by default, and it's common to have a validation in the model that ensures foreign ID values are greater than zero.
In my example, I would like to have the option to not have a foreign ID set (i.e. it is not [yet] linked to a another 'owning' record).
Would it be appropriate to remove the validation from the model, and then set the value of the foreign ID to zero in this case, indicating that it is not assigned?
For some reason, I don't seem to be able to find this stated in documentation anywhere, maybe I'm using the wrong terminology, or it's too obvious to document ;-)
Related
Can a table contain only foreign keys and from other table's attribute, or those foreign keys will be mark as table's primary key.
A primary key serves to uniquely identify a row, and is helpful for locationg existing data for update/delete purposes, or when other data refers to it
Data that only refers to something else can certainly have foreign keys but no primary keys; think about a log - row - "customer X viewed product Y at time Z" - it might only ever refer to other data but have no need to be referred to uniquely in and of itself; those entries are written, and maybe analyzed later in aggregate but there isn't a need to change anything about them or prevent "duplications" (if you only log to a minute precision, the customer might view the same product several times in the minute - interesting in itself, and you don't care about the apparent duplication)
Bid is something like a log table, if bids cannot be deleted or updated (I assume the user makes another bid entry if they want to pay more?) so it would appear to be OK for it not to have a primary key
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.
This seems like a desirable feature but I can't seem to figure out how I would do it while the foreign key is a part of the primary key (composite key).
The table is a simple junction table for a many to many relationship referencing User.id and Access.id referencing functions a user has access to:
Column | References
user user.id
access access.id
Therefore there can be many entries for each user and each access level. To simplify things for "superusers" I wanted to have a NULL value for access which would mean they have access to every page (this is the only way I could figure how to enter a value that didn't reference a row in the access table). The problem is MySQL won't allow a NULL value as a part of the primary key.
Is there a way around the NULL issue with primary keys or is there another way to reference every row (or no rows) in a foreign key? The only other way around this I can think of would be to disable the foreign key or have to add a row for every access.id in the table. Either of which would be undesirable.
Presumably you have a superuser flag on your user table. You could UNION a Cartesian join of each superuser and the set of available access IDs into whatever query you need this for.
Depending on what you're doing, you could also just not store the access for a superuser in the database and treat them differently in code - i.e. ignore the access check once you've established them as SU. Depends on your application though.
I think NULL is allowed and you can use it as a unique combination along with user.id. But I am not sure if this is a good way to do this. I mean you can store the super user setting in a column and use it in the code than here.
I'm designing a database (for use in mysql) that permits new user-defined attributes to an entity called nodes.
To accomplish this I have created 2 other tables. One customvars table that holds all custom attributes and a *nodes_customvars* that define the relationship between nodes and customvars creating a 1..n and n..1 relationship.
Here is he link to the drawed model: Sketched database model
So far so good... But I'm not able to properly handle INSERTs and UPDATEs using separate IDs for each table.
For example, if I have a custom attribute called color in the *nodes_customvars* table inserted for a specific node, if I try to "INSERT ... ON DUPLICATE KEY UPDATE" either it will always insert or always update.
I've thinked on remove the "ID" field from the *nodes_customvars* tables and make it a composite key using nodes id and customvars id, but I'm not sure if this is the best solution...
I've read this article, and the comments, as well: http://weblogs.sqlteam.com/jeffs/archive/2007/08/23/composite_primary_keys.aspx
What is the best solution to this?
EDIT:
Complementing: I don't know the *nodes_customvars* id, only nodes id and customvars id. Analysing the *nodes_customvars* table:
1- If I make nodes id and/or customvars id UNIQUE in this table, using "INSERT ... ON DUPLICATE KEY UPDATE" will always UPDATE. Since that multiple nodes can share the same customvar, this is wrong;
2- If I don't make any UNIQUE key, "INSERT ... ON DUPLICATE KEY UPDATE" will always INSERT, since that no UNIQUE key is already found in the statement...
You have two options for solving your specific problem of the "INSERT...ON DUPLICATE KEY" either always inserting or updating as you describe.
Change the primary to be a composite key using nodeId and customvarId (as suggested by SyntaxGoonoo and in your question as a possible option).
Add a composite unique index using nodeId and customvarId.
CREATE UNIQUE INDEX IX_NODES_CUSTOMVARS ON NODES_CUSTOMVARS(nodeId, customvarId);
Both of the options would allow for the "INSERT...ON DUPLICATE KEY" functionality to work as you require (INSERT if a unique combination of nodeId and customvarId doesn't exist; update if it does).
As for the question about whether to have a composite primary key or a separate primary key column with an additional unique index, there are many things to consider in the design. There's the 1NF considerations and the physical characteristics of the database platform you're on and the preference of the ORM you happen to be using (if any). Given how InnoDB secondary indexes work (see last paragraph at: http://dev.mysql.com/doc/refman/5.0/en/innodb-index-types.html), I would suggest that you keep the design as you currently have it and add in the additional unique index.
HTH,
-Dipin
You current entity design breaks 1NF. This means that your schema can erroneously store duplicate data.
nodes_customvars describes the many-to-many relationship between nodes and customvars. This type of table is sometimes referred to as an auxiliary table, because its contents are purely derived from base tables (in this case nodes and customvars).
The PK for an auxiliary table describing a many-to-many relationship should be a composite key in order to prevent duplication. Basically 1NF.
Any PK on a table is inherently UNIQUE. regardless of whether it is a single, or composite key. So in some ways your question doesn't make sense, because you are talking about turning the UNIQUE constraint on/off on id for nodes and customvars . Which you can't do if your id is actually a PK.
So what are you actually trying to achieve here???
I'm new to foreign key constraints. I will formulate a simple example to explain my situation.
I have a table user and a table entry. In user there is a user.firstEntry which is a foreign key to entry.EntryID. In entry there is a entry.userID which is a foreign key to the user.userID table. These IDs are all auto increment values.
Are cycles like that forbidden? Then I will have to change the design?
I am not able to insert some valid entry into both tables, because the first insert already says that there's a problem with the constraints. Auto commit is off.
What shall I do?
Thanks
Bit strange design, but you can do this :
When creating a User, set firstEntry to NULL.
Insert an Entry with that user's id.
Update Users and set firstEntry to the id of the inserted entry.
Both user and entry need the other to be already created beforehand. and since either cant be created without the other, you will have this problem IF foreign constraints check is on that is.
Whatever I can understand from your question, each user seems to have multiple entries. So your table design could look like Table_User(user_id(pk), user_name etc) and the entry table could be Table_Entry(entry_id(pk), entry_whatever,...,user_id(fk to user table)) As it seems the user is independent but the entries are dependent on users.
A foreign key constraint is supposed to prevent your from adding invalid data into the foreign key column.
In most cases it will check to see if the value actually exists in the specified table. Because you have a cycle in your user and entry table, when you attempt to create a entry it will check to see if the value of entry.userID exists in the user table. It will do the same when you attempt to add a new user, it will check the entry table for the value you entered for user.firstEntry. If both user and entry are new there is no way to link the two because of your cycle. A new entry record needs an existing user and a new user record needs an existing entry. When both tables are empty I don't think you will be able to satisfy the constraint.
I would suggest keeping the foreign key to userID in the entry table (since I'm assuming entries are linked to users) and finding some other way to represent a user's first entry. Maybe an user_entry_history table or something along those lines.
DISCLAIMER - It's been awhile since I messed with Database design.