My question specifically about sql-server, but probably can be answered by anyone with any database background
If I want table A to have a 1:1 relationship with table B on a certain column, should I somehow modify the CREATE TABLE statement to identify this relationship or is this something that is not done at all (and rather it is handled by logic)?
EDIT
The second part of my question is: what is the point of embedding this into the code? why not just handle it logically on selects/updates?
All you need to do is have the column in Table A be a foreign key to the primary key of Table B:
create table TableB (
Id int primary key identity(1,1),
Name varchar(255))
create table TableA (
Id int primary key identity(1,1),
Name varchar(255),
TableBRelation int unique,
foreign key (TableBRelation) references TableB (Id))
The SQL may not be perfect but you should be able to get the idea.
As for why you would want to do this in the database rather than just application logic:
Other databases or developers may try to access your database. Do you want them to be able to create invalid data that may break your application? No. That's one of the points of referential integrity.
At some point, somebody is going to have to maintain your application. Defining your keys at the database level will clearly identify relationships between your data rather than requiring the develop to dig through your application code.
To create a 1:1 relationship just make the B table column a foreign key or unique. This will ensure that there can be only one column in table B that matches the PK field in table A and that way you effectively get a 1:1 relationship...
You can setup a foreign key and add a constraint for it to be unique. This would setup a 1:1 relationship between your tables.
Related
I have got two questions when designing a database for a sales system.
Is it possible to have a isolated table, which means a table does not have relationship with all other tables?
How to solve the following issue:
Table: SalesOrderDetail, Table: InventoryTrans
Every record in SalesOrderDetail will insert into InventoryTrans, but not all records in InventoryTrans are from SalesOrderDetail. Because other tables may also insert records into the InventoryTrans.
Therefore, I want to add a reference column SalesOrderDetailID to InventoryTrans table, but does not specify FK constraint. Because if the record is not from SalesOrderDetail table, then the SalesOrderDetailID should be null.
Is this the right design?
Yes, you can have a table that has no foreign key references to other tables. A table that stores various configuration settings is probably the most common, but there are others.
The column InventoryTrans.SalesOrderDetailID can be a nullable foreign key reference. But you haven't provided enough detail to tell whether that's a good design decision. Making an educated guess, I'd say probably not. (Other kinds of transactions would probably benefit from a foreign key reference.)
First, I want to talk a little about the Foreign key constraint rule and how helpful it is. Suppose I have two tables, a primary table with the primary column called ID, the other table is the foreign one which also has a primary column called ID. This column in the foreign table refers to the ID column in the primary table. If we don't establish any Foreign key relation/constraint between those tables, we may fall foul of many problems related to integrity.
If we create the foreign key relation for them, any changes to the ID column in primary table will 'auto' reflect to the ID column in the foreign table, changes here can be made by DELETE, UPDATE queries. Moreover, any changes to the ID in the foreign table should be constrained by the ID column in the primary table, for example there shouldn't any new value inserted or updated in the ID column of the foreign table unless it does exist in the ID column of the primary table.
I know that SQLite doesn't support foreign key constraint (with full functions as detailed above) and I have to use TRIGGER to work around this problem. I have used TRIGGER to work around successfully in one way (Any changes to the ID column in the primary table will refect to the ID column in the foreign table) but the reverse way (should throw/raise any error if there is a confict occurs, for example, there are only values 1,2,3 in the ID column of the primary table, but the value 2 in the ID column of the foreign table is updated to 4 -> not exist in the primary table -> should throw error) is not easy. The difficult is SQLite doesn't also support IF statement and RAISERROR function. If these features were supported, I could work around easily.
I wonder how you can use SQLite if it doesn't support some important features? Even working around by using TRIGGER is not easy and I think it's impossible, except that you don't care about the reverse way. (In fact, the reverse way is not really necessary if you set up your SQL queries carefully, but who can make sure? Raising error is a mechanism reminding us to fix and correct and making it work exactly without corrupting data and the bugs can't be invisible.
If you still don't know what I want, I would like to have some last words, my purpose is to achieve the full functionality of the Foreign key constraint which is not supported in SQLite (even you can create such a relationship but it's fake, not real as you can benefit from it in SQL Server, SQL Server Ce, MS Access or MySQL).
Your help would be highly appreciated.
PS: I really like SQLite because it is file-based, easy to deploy, supports large file size (an advantage over SQL Server Ce) but some missing features have made me re-think many times, I'm afraid if going for it, my application may be unreliable and corrupt unpredictably.
To answer the question that you have skillfully hidden in your rant:
SQLite allows the RAISE function inside triggers; because of the lack of control flow statements, this must be used with a SELECT:
CREATE TRIGGER check_that_id_exists_in_parent
BEFORE UPDATE OF id ON child_table
FOR EACH ROW
BEGIN
SELECT RAISE(ABORT, 'parent ID does not exist')
WHERE NOT EXISTS (SELECT 1
FROM parent_table
WHERE id = NEW.id);
END;
I'm trying to set up an EDM on an existing SQL Server infrastructure, and came across a problem.
The EDM will not resolve a PK-FK relationship to a composite foreign key.
My DB table structure looks something like this (names changed to protect the innocent):
I have a PERSONS table containing an INT column called PerID (PK)
I have an OFFICE table containing an INT column called OffID (PK)
I am tying these tables together using a table called OFFICEPERSONS, creating a many-to-many relationship between PERSONS and OFFICE. This table has two INT columns, PerID and OffID, which together form a composite primary key.
I have a table called OFFICELOCATION that contains two INT columns, LocID and OffID. These two columns comprise a composite primary key. Additionally, OffID is also a FK to the OFFICE table.
Finally, I have a table called OFFICEPERSONSLOCATION. This table has three INT columns: PerID, OffID, and LocID. All three columns comprise a composite primary key. LocID and OffID provide a FK relationship to OFFICELOCATION, and OffID and PerID provide a FK relationship to OFFICEPERSONS.
With me so far? Hopefully, I haven't lost you yet. When all is said and done, my structure looks like this:
This structure works great in SQL Server. In EDM? Not so much. It will NOT allow me to construct the relation between OFFICEPERSONSLOCATION and OFFICEPERSONS. I get the following error:
Error 6037: Foreign key constraint 'FK_OFFICEPERSONSLOCATION_OFFICEPERSONS' has been omitted from the storage model. Column 'OffID' of table 'Model.Store.OFFICEPERSONSLOCATION' is a foreign key participating in multiple relationships. A one-to-one Entity Model will not validate since data inconsistency is possible.
Huh? Data inconsistency?!? How?
How do I get my entity framework to recognize this?
I agree that it is the entity framework's problem, and the problem is stupid. Even if you have the UPDATE CASCADE to "no action", it is not like you could create an inconsistency, but no, it claims that you can somehow.
In any case, in this situation, if you are willing to use surrogate keys instead of composite keys, you can get around this, because the only place to change the ID reference is in the main table.
In this case, OffID could be "inconsistent", but by using ID's in the OFFICEPERSONS and OFFICELOCATIONS tables (and therefore reference in OFFICEPERSONSLOCATION), you are forced to have the OffId managed in its primary table.
I have two tables:
User (username, password)
Profile (profileId, gender, dateofbirth, ...)
Currently I'm using this approach: each Profile record has a field named "userId" as foreign key which links to the User table. When a user registers, his Profile record is automatically created.
I'm confused with my friend suggestion: to have the "userId" field as the foreign and primary key and delete the "profileId" field. Which approach is better?
Foreign keys are almost always "Allow Duplicates," which would make them unsuitable as Primary Keys.
Instead, find a field that uniquely identifies each record in the table, or add a new field (either an auto-incrementing integer or a GUID) to act as the primary key.
The only exception to this are tables with a one-to-one relationship, where the foreign key and primary key of the linked table are one and the same.
Primary keys always need to be unique, foreign keys need to allow non-unique values if the table is a one-to-many relationship. It is perfectly fine to use a foreign key as the primary key if the table is connected by a one-to-one relationship, not a one-to-many relationship. If you want the same user record to have the possibility of having more than 1 related profile record, go with a separate primary key, otherwise stick with what you have.
Yes, it is legal to have a primary key being a foreign key. This is a rare construct, but it applies for:
a 1:1 relation. The two tables cannot be merged in one because of different permissions and privileges only apply at table level (as of 2017, such a database would be odd).
a 1:0..1 relation. Profile may or may not exist, depending on the user type.
performance is an issue, and the design acts as a partition: the profile table is rarely accessed, hosted on a separate disk or has a different sharding policy as compared to the users table. Would not make sense if the underlining storage is columnar.
Yes, a foreign key can be a primary key in the case of one to one relationship between those tables
I would not do that. I would keep the profileID as primary key of the table Profile
A foreign key is just a referential constraint between two tables
One could argue that a primary key is necessary as the target of any foreign keys which refer to it from other tables. A foreign key is a set of one or more columns in any table (not necessarily a candidate key, let alone the primary key, of that table) which may hold the value(s) found in the primary key column(s) of some other table. So we must have a primary key to match the foreign key.
Or must we? The only purpose of the primary key in the primary key/foreign key pair is to provide an unambiguous join - to maintain referential integrity with respect to the "foreign" table which holds the referenced primary key. This insures that the value to which the foreign key refers will always be valid (or null, if allowed).
http://www.aisintl.com/case/primary_and_foreign_key.html
It is generally considered bad practise to have a one to one relationship. This is because you could just have the data represented in one table and achieve the same result.
However, there are instances where you may not be able to make these changes to the table you are referencing. In this instance there is no problem using the Foreign key as the primary key. It might help to have a composite key consisting of an auto incrementing unique primary key and the foreign key.
I am currently working on a system where users can log in and generate a registration code to use with an app. For reasons I won't go into I am unable to simply add the columns required to the users table. So I am going down a one to one route with the codes table.
It depends on the business and system.
If your userId is unique and will be unique all the time, you can use userId as your primary key. But if you ever want to expand your system, it will make things difficult. I advise you to add a foreign key in table user to make a relationship with table profile instead of adding a foreign key in table profile.
Short answer: DEPENDS.... In this particular case, it might be fine. However, experts will recommend against it just about every time; including your case.
Why?
Keys are seldomly unique in tables when they are foreign (originated in another table) to the table in question. For example, an item ID might be unique in an ITEMS table, but not in an ORDERS table, since the same type of item will most likely exist in another order. Likewise, order IDs might be unique (might) in the ORDERS table, but not in some other table like ORDER_DETAILS where an order with multiple line items can exist and to query against a particular item in a particular order, you need the concatenation of two FK (order_id and item_id) as the PK for this table.
I am not DB expert, but if you can justify logically to have an auto-generated value as your PK, I would do that. If this is not practical, then a concatenation of two (or maybe more) FK could serve as your PK. BUT, I cannot think of any case where a single FK value can be justified as the PK.
It is not totally applied for the question's case, but since I ended up on this question serching for other info and by reading some comments, I can say it is possible to only have a FK in a table and get unique values.
You can use a column that have classes, which can only be assigned 1 time, it works almost like and ID, however it could be done in the case you want to use a unique categorical value that distinguish each record.
I designed a database to use GUIDs for the UserID but I added UserId as a foreign key to many other tables, and as I plan to have a very large number of database inputs I must design this well.
I also use ASP Membership tables (not profiles only membership, users and roles).
So currently I use a GUID as PK and as FK in every other table, this is maybe bad design?
What I think is maybe better and is the source of my question, should I add in Users table UserId(int) as a primary key and use this field as a foreign key to other tables and user GUID UserId only to reference aspnet_membership?
aspnet_membership{UserID(uniqueIdentifier)}
Users{
UserID_FK(uniqueIdentifier) // FK to aspnet_membership table
UserID(int) // primary key in this table --> Should I add this
...
}
In other tables user can create items in tables and I always must add UserId for example:
TableA{TableA_PK(int)..., CreatedBy(uniqueIdentifier)}
TableB{TableB_PK(int)..., CreatedBy(uniqueIdentifier)}
TableC{TableC_PK(int)..., CreatedBy(uniqueIdentifier)}
...
Ultimately the answer is that it really depends.
Microsoft have documented the performance differences of each here. While the article differs slightly to your situation, as you have to use a UNIQUEIDENTIFIER to link back to asp membership, many of the discussion points still apply.
If you have to create your own users table anyway it would make more sense to have your own int primary key, and use the GUID as a foreign key. It keeps separate entities separate. What if at some point in the future you wanted to add a different membership to a user? You would then need to update a primary key, which would have to cascade to any tables referencing this and could be quite a performance hit. If it is just a unique column in your users table it is a simple update.
All binary datatypes (uniqueidetifier is binary(16)) are fine as foreign keys. But GUID might cause another small problem as primary key. By default primary key is clustered, but GUID is generated randomly not sequentially as IDENTITY, so it will frequently split IO pages, that cause performance degradation a little.
I'd go ahead with your current design.
If you're worried because of inner joins performance in your queries because of comparing strings instead of ints, nowadays there is no difference at all.