I have question regarding the Associative or the join table we create for the relationship between two entities.
I know the that the foreign key can be NULL in the join table.But should the join table only contain the relationships.As in if in a bank there is a customer(key-id) and a loan(key-id) entity.Let borrow be the relationship between it.Now suppose there are customers who "haven't taken a loan".
So should i take those customers id in the borrow table and the corresponding foreign key for loan-id to be NULL.Or i shouldn't take those customers in the borrow table.
And what can be a good primary key for the join table.And is the primary key for the join table required.
You are right having a join table between customer and loan.
But you do not need to do anything in this table until there is an actual borrow.
Your primary key for the borrow table should be a composite primary key. Made of customer_id and load_id
Customer
customer_id | name | ...
1 | Jon | ...
2 | Harry | ...
Loan
load_id | amount | ...
1 | 1000 | ...
2 | 2000 | ...
Borrow
customer_id | load_id
1 | 1
1 | 2
In this example you can see that Jon has to loans and respectivley there are two records in the borrow table. Harry is a customer, but he has no loan and so there is no record in the borrow table for him.
Every table (base or query result) has a parameterized statement (aka predicate):
customer [customer_id] has taken out loan [loan_id]
Borrows(customer_id,loan_id)
When you plug in a row like VALUES (customer_id,loan_id) (8,3) you get a statement (aka proposition):
customer 8 has taken loan 3
The rows that make true statements go in the table. The rows that make false statements stay out of the table. So every row that fits in a table makes a statement whether it is in it or not!
The table predicate corresponds to an application relationship wher parameters correspond to columns. A row says something about those values and about identified application entities via them.
You pick the application relationships ie table predicates. Then you look at an application situation and put every true row into the tables. Or you look at the tables and see what things are true (per present rows) and false (per absent rows).
Queries also have predicates per their conditions and their logical and relational operators. And their results hold the rows that make them true.
So when someone hasn't taken a loan their customer_id doesn't appear in any row in Borrows. And when a loan has not been taken by anyone then its loan_id doesn't appear in any row of Borrows.
If a column can be null then its table's predicate often looks like:
[name] IS NULL AND [customer_id] identifies a customer
OR [name] IS NOT NULL
AND [customer_id] identifies a customer
AND customer [customer_id] is named [name]
Customer(customer_id NOT NULL,name NULL)
(Using NULL in other ways gets even more complicated. And we try to remove NULLs in queries as near to when they're introduced as possible.)
We determine candidate keys like usual and pick one as a primary key as ususal. Eg the key for Borrows is (customer_id,name) because that set's values are unique and there is no smaller unique subset. But determining keys involves columns that are UNIQUE NOT NULL (which PRIMARY KEY is just a synonym for as a constraint). But we don't ever need to use NULL in a column because instead of a predicate/table like the above we can have two:
[customer_id] identifies a customer
Customer(customer_id NOT NULL)
customer [customer_id] is named [name]
Customer(customer_id NOT NULL,name NOT NULL)
Just like always a row goes in a table if and only if it makes a true statement.
See this.
Related
I have a database in which i have two tables:
CREATE TABLE Transactions (
ID BIGINT IDENTITY(1,1) NOT NULL,
AccountID BIGINT NOT NULL,
Amount BIGINT NOT NULL,
CONSTRAINT PK_Transactions PRIMARY KEY CLUSTERED (ID ASC,AccountID ASC),
CONSTRAINT FK_Transaction_Account FOREIGN KEY (AccountID) REFERENCES Accounts(ID)
);
CREATE TABLE Accounts (
ID BIGINT IDENTITY(1,11) NOT NULL,
Balance BIGINT NOT NULL,
CONSTRAINT PK_Accounts PRIMARY KEY (ID)
);
Transactions are inserted to their table by a stored procedure i wrote, so that two rows are generated when Account 1 transfers 25 "coins" to Account 21:
ID | AccountID | Amount
-------------------------
1 | 1 | -25
-------------------------
1 | 21 | 25
In the above schema, i want the first row to reference the bottom row based on ID and the AccountID being unequal to the AccountID of the bottom row.
And vica versa.
What i want to do would look something like this:
CONSTRAINT FK_Transaction_Counterpart FOREIGN KEY (ID) REFERENCES Transactions(ID) WHERE thisRow.AccountID != referencedRow.AccountID
I haven't found this possibility in the documentation on the table constraints.
So both out of curiosity and intent to use this i ask, is this possible? And if yes, how?
Edit:
Answers reflect that this is not possible, and i should adjust my design or intentions.
I think i will settle with assigning the two transaction rows to each other in the functional code.
A traditional foreign key can't be conditional (i.e. no WHERE clause attached). In your case, I'd probably just make sure that the inserts are atomic (in the same transaction) so that there'd be no possibility of only one of them inserting.
If the data model you are trying to implement is:
One transaction (ID) has two and only two entries in table Transactions
For the two rows of a given Transaction ID, the AccountIDs cannot be the same
Then one perhaps overly-complex way you could enforce this business rule within the database table structures would be as follows:
Table Accounts, as you have defined
Table Transactions, as you have defined
New table TransactionPair with:
Columns (all are NOT NULL)
ID
LowAccountID
HighAccountID
Constraints
Primary key on ID (only one entry per Transaction ID)
Foreign key on (ID, LowAccountID) into Transactions
Foreign key on (ID, HighAccountID) into Transactions
Check constraint on the row such that LowAccountID < HighAccountID
Process:
Add pair of rows to Transactions table
Add single row to TransactionPair referencing the rows just added
If that row cannot be added, something failed, roll everything back
Seems neat and tidy, but quite possibly overly complex. Your mileage may vary.
I'm creating a clinic management system where I need to store Medical History for a patient. The user can select multiple history conditions for a single patient, however, each clinic has its own fixed set of Medical History fields.
For example:
Clinic 1:
DiseaseOne
DiseaseTwo
DiseaseThree
Clinic 2:
DiseaseFour
DiseaseFive
DiseaseSize
For my Patient visit in a specific Clinic , the user should be able to check 1 or more Diseases for the patient's medical history based on the clinic type.
I thought of two ways of storing the Medical History data:
First Option:
Add the fields to the corresponding clinic Patient Visit Record:
PatientClinic1VisitRecord:
PatientClinic1VisitRecordId
VisitDate
MedHist_DiseaseOne
MedHist_DiseaseTwo
MedHist_DisearThree
And fill up each MedHist field with the value "True/False" based on the user input.
Second Option:
Have a single MedicalHistory Table that holds all Clinics Medical History detail as well as another table to hold the Patient's medical history in its corresponding visit.
MedicalHistory
ClinicId
MedicalHistoryFieldId
MedicalHistoryFieldName
MedicalHistoryPatientClinicVisit
VisitId
MedicalHistoryFieldId
MedicalHistoryFieldValue
I'm not sure if these approaches are good practices, is a third approach that could be better to use ?
If you only interested on the diseases the person had, then storing the false / non-existing diseases is quite pointless. Not really knowing all the details doesn't help getting the best solution, but I would probably create something like this:
Person:
PersonID
Name
Address
Clinic:
ClinicID
Name
Address
Disease:
DiseaseID
Name
MedicalHistory:
HistoryID (identity, primary key)
PersonID
ClinicID
VisitDate (either date or datetime2 field depending what you need)
DiseaseID
Details, Notes etc
I created this table because my assumption was that people have most likely only 1 disease on 1 visit, so in case there's sometimes several, more rows can be added, instead of creating separate table for the visit, which makes queries most complex.
If you need to track also situation where a disease was checked but result was negative, then new status field is needed for the history table.
If you need to limit which diseases can be entered by which clinic, you'll need separate table for that too.
Create a set of relational tables to get a robust and flexible system, enabling the clinics to add an arbitrary number of diseases, patients, and visits. Also, constructing queries for various group-by criteria will become easier for you.
Build a set of 4 tables plus a Many-to-Many (M2M) "linking" table as given below. The first 3 tables will be less-frequently updated tables. On each visit of a patient to a clinic, add 1 row to the [Visits] table, containing the full detail of the visit EXCEPT disease information. Add 1 row to the M2M [MedicalHistory] table for EACH disease for which the patient will be consulting on that visit.
On a side note - consider using Table-Valued Parameters for passing a number of rows (1 row per disease being consulted) from your front-end program to the SQL Server stored procedure.
Table [Clinics]
ClinicId Primary Key
ClinicName
-more columns -
Table [Diseases]
DiseaseId Primary Key
ClinicId Foreign Key into the [Clinics] table
DiseaseName
- more columns -
Table [Patients]
PatientId Primary Key
ClinicId Foreign Key into the [Clinics] table
PatientName
-more columns -
Table [Visits]
VisitId Primary Key
VisitDate
DoctorId Foreign Key into another table called [Doctor]
BillingAmount
- more columns -
And finally the M2M table: [MedicalHistory]. (Important - All the FK fields should be combined together to form the PK of this table.)
ClinicId Foreign Key into the [Clinics] table
DiseaseId Foreign Key into the [Diseases] table
PatientId Foreign Key into the [Patients] table
VisitId Foreign Key into the [Visits] table
I am fairly green when it comes to working with Access and databases in general.
I am asking for your help in figuring out how to set the correct relationships for three tables:
Table 1 contains:
(no unique ID)
SalesTripID
EmployeeName
StartDate
EndDate
*Each record on this table is related to 1 specific employee's 1 specific sales trip
Table 2 contains:
HotelName
HotelStart
HotelEnd
HotelTotal
*This table may contain multiple records that belong to only 1 record on table 1 (for instance, an employee would stay at 2 hotels during their sales trip)
Table 3 contains:
(no unique ID)
MealVendor
MealDate
MealTotal
*This table, similar to Table 2, may have multiple records in it that are tied to the 1 SalesTripID
How do I set something up to show me each SalesTripID, the multiple Table 2, and the multiple Table 3 records associated with it? Do I need to add a Primary Key anything other than Table 1? Is writing a query involved to display the information? Because I am so green, any and all feedback is welcome.
The following is my recommendation:
Add a SalesTripId field on tables 2,3. This is called a ForeignKey.
If SalesTripId in Table1 is not unique (i.e. each employee can have a trip with the same Id as another employee), add another field (Id) in Table1. You can use Access' AutoNumber type for that field.
I recommend always having a primary key in your tables. But you can skip the Id fields in tables 2,3.
I will do my best to lay this out in text. Essentially, we have an application that tracks actions performed by users. Each action has it's own table since each action has different parameters that need to be stored. This allows us to store those extra attributes and run analytics on the actions across multiple or single users rather easily. The actions are not really associated with each other other than by what user performed these actions.
Example:
ActionTableA Id | UserId | AttributeA | AttributeB
ActionTableB Id | UserId | AttributeC | AttributeD | AttributeE
ActionTableC Id | UserId | AttributeF
Next, we need to allocate a value to each action performed by the user and keep a running total of those values.
Example:
ValueTable: Id | UserId | Value | ActionType | ActionId
What would be the best way to link the value in the value table to the actual action performed? We know the action type (A, B, C) - but from a SQL design perspective, I cannot see a good way to have an indexed relationship between the Values of the actions in the ActionsTable and the actual actions themselves. The only thing that makes sense would be to modify the ValueTable to the following:
ValueTable
Id | UserId | Value | ActionType | ActionAId(FK Nullable) | ActionBId(FK Nullable) | ActionCId(FK Nullable)
But the problem I have with this that only one of the 3 actionTableId columns would have a value, the rest would be Null. Additionally, as action types are added, the columns in the value table would too. Lastly, to programatically find the data, I would either a) have to check the ActionType to get the appropriate column for the Id or b) scan the row and pick the non-null actionId.
Is there a better way/design or is this just 'the way it is' for this particular issue.
EDIT
Attached is a diagram of the above setup:
Sorry for the clarity issues, typing SQL questions is always challenging. So I think your comment gave me an idea of something... I could have an SystemActionId table that essentially has an auto-generated value
SystemActions: Id | Type
Then, each ActionTable would have an additional FK to the SystemAction table. Lastly, in the ValueTable - associate it to the SystemActions table as well. This would allow us to tie values to specific actions. I would need to join the action tables to the system actions table where
JOIN (((SystemActions.Id = ActionTableA.Id) JOIN (SystemActions.Id = ActionTableB.Id)) JOIN (SystemActions.Id = ActionTableC.Id)
crappy quick sql syntax
Is this what you were alluding to in the answer below? A snapshot of what that could potentially look like:
Your question is a little unclear, but it looks like you should either have a (denormalized) value column in each action table, or have an artificial key in the value table that is keyed to by each of the seperate action tables.
You have essentially a supertype/subtype structure, or an exclusive arc. Attributes common to all actions bubble "up" into the supertype (the table "actions"). Columns unique to each subtype bubble "down" into the distinct subtypes.
create temp table actions (
action_id integer not null,
action_type char(1) not null check (action_type in ('a', 'b', 'c')),
user_id integer not null, -- references users, not shown.
primary key (action_id),
-- Required for data integrity. See below.
unique (action_id, action_type)
);
create temp table ActionTableA (
action_id integer primary key,
-- default and check constraint guarantee that only an 'a' row goes
-- in this table.
action_type char(1) not null default 'a' check (action_type = 'a'),
-- FK guarantees that this row matches only an 'a' row in actions.
-- To make this work, you need a UNIQUE constraint on these two columns
-- in the table "actions".
foreign key (action_id, action_type)
references actions (action_id, action_type),
attributeA char(1) not null,
attributeB char(1) not null
);
-- ActionTableB and ActionTableC are similar.
create temp table ValueTable (
action_id integer primary key,
action_type char(1) not null,
-- Since this applies to all actions, FK should reference the supertype,
-- which is the table "actions". You can reference either action_id alone,
-- which has a PRIMARY KEY constraint, or the pair {action_id, action_type},
-- which has a UNIQUE constraint. Using the pair makes some kinds of
-- accounting queries easier and faster.
foreign key (action_id, action_type)
references actions (action_id, action_type),
value integer not null default 0 check (value >= 0)
);
To round this out, build updatable views that join the supertype to each subtype, and have all users use the views instead of the base tables.
I would just have a single table for actions, to be honest. Is there a reason (other than denormalization) for having multiple tables? Especially when it will increase the complexity of your business logic?
Are the attribute columns significant in the context of the schema? Could you compress it into an object storage column "attributes"?
Actions: actionID, type, attributes
I think you need something similar to an Audit Trail. Can we have a simple design so that all the actions will be captured in a singe table ?
If the way you want it to work is that for every time a user performs action A you insert a new row in table ActionTableA and a row in ValueTable, and having them both linked, why not have a value column in each action table? This would work only if you want to insert a new row each time the user performs the action rather than if you want to update the value if the user performs the same action again. It seems overly complicated to have a separate table for values if it can be stored in a column. On the other hand if a "value" is a set of different pieces of data (or if you want to have all values in one place) then you do need an extra table but I would still have a foreign key column pointing from the action tables to the value table.
Ok. So I know what a primary key in DB is. If you have a table in a database, a primary key is a single value that is unique to each row in your table. For example:
id | name | whatever
-------------------------
1 Alice ....
2 Bob ....
45 Eve ....
988 .... ....
So I need a good, simple example to explain what exactly a foreign key is. Because I just don't get it :)
Edit: OK it's pretty easy, I guess I was over-complicating the problem.
So one final question, the only restriction on foreign keys is that it they are a valid primary key value in the table I am referring to?
A foreign key is a field that points to a primary key of another table.
Example:
Table Name - Users
UserID UserName UserRoleID
1 JohnD 1
2 CourtneyC 1
3 Benjamin 2
Table Name - UserRoles
UserRoleID Desc
1 Admin
2 Moderator
You can see that Users.UserRoleID is a foreign key which points to the primary key UserRoles.UserRoleID
The use of foreign keys makes setting up relationships on other tables simple, allowing you to link together the data of multiple tables in a nice way:
Example:
SELECT
a.UserID,
a.UserName,
b.Desc as [UserRole]
FROM
Users a INNER JOIN
UserRoles b ON a.UserRoleID = b.UserRoleID
Output would then be:
UserID UserName User Role
1 JohnD Admin
2 CourneyC Admin
3 Benjamin Moderator
Let's say you have another field, which is the home city:
id | name | city
-------------------------
1 Alice San Francisco
2 Bob New York
45 Eve New York
988 Bill San Francisco
Now, it does not make sense to repeat the same cities in many rows. This could lead you to typos, excessive space usage, difficulties to bring up results among other problems. So you use a foreign key:
id | name | fk_city
-------------------------
1 Alice 1
2 Bob 2
45 Eve 2
988 Bill 1
home city table:
id | name
-------------------------
1 | San Francisco
2 | New York
Hope it makes things clearer for you. :-)
Update: about your final question: Yes. :-)
A foreign key is a column in one table that should uniquely identify something in another table. Thus, the values should correspond to primary keys in that other table.
For example, if you have a table of students taking courses, every record would include a student id and a course id. These are foreign keys into a student table (where there is one record for each student id), and a courses table (where there is one record for each course id).
Referential integrity means that all your foreign keys actually correspond to primary keys in these target tables. For example, all the student ids and course ids in your registration table correspond to real student ids and course ids.
id | name | whatever | countryid
-------------------------------------
1 Alice .... 13
2 Bob .... 42
45 Eve .... 1
988 .... .... 2
id | countryid
----------------
1 Japan
2 Spain
13 Norway
42 Italy
The foreign key points from the person table (first) to a row in the country table (second)
A foreign key is the primary key from another table stored on your table. Say you have a table of customers and a table of orders. The CustomerId is likely the primary key on the customer table, and the OrderId is likely the primary key on the order table. But on the order table you need to know the customer for this order, no? Therefore you need to store the CustomerId on the order table. In this case the CustomerId on the order table is a foreign key.
I would point out that there is no requirement that a primary key (and therefore a foreign key) be a single column. It's simpler, sure. But I've worked on enterprise systems where the primary key was 11 columns long, and I'm sure there are examples longer than that. That is, you needed to know the value for 11 different columns before you can uniquely identify the row.
In a relational database a one-to-many relationship is implemented by having the child table reference the ID of the parent table. The parent ID in the Child table is called a Foreign Key as it references a primary key of another table.
A foreign key is a field that references another table in the database. For example, suppose you had 2 tables, PERSON and ADDRESS. There is a field in PERSON called ID and a field in ADDRESS called PERSON_ID. You would make PERSON_ID refer to PERSON.ID as a foreign key. What this means is that you can't have an address that is not connected to a person, since the value in the ADDRESS.PERSON_ID field must exist in the table PERSON.
using your table example, assume you have another table:
cartid | id | itemid
-----------------------
100 1 abc
101 1 cde
in this table, the primary key is the cartid, the foreign key is the id, which would be linked to your first table. user 1 has two carts, each cart having one item each.
a foreign key is the what you use to link two or more tables that have related information to each other.