I have the following structure in my database:
Area:
----------------
Id: (PK, bigint)
AreaName: (varchar)
Post:
----------------
Id: (PK, bigint)
AreaId: (FK, bigint)
Title: (varchar)
Text: (varchar)
Comment:
----------------
Id: (PK, bigint)
PostId: (FK, bigint)
Text: (varchar)
Since I will have many scenarios where I need to query comments by Area, my question is this -
Is it better to JOIN through my Post table to get to Area for Comments, or would it be better to modify my Comment table like so:
Comment:
----------------
Id: (PK, bigint)
AreaId: (FK, bigint)
PostId: (FK, bigint)
Text: (varchar)
What are the best practices with "cascading" foreign keys instead of joining for purposes of querying? My gut tells me that this is a bad idea, but I can't deny that it would make a lot of my queries easier.
Should I be constructing a View that does this? Also, is there a term for this "cascading" foreign key concept? I had a hard time coming up with information on this despite feeling like it would be a common question.
The following question asks something similar:
Three level database - foreign keys
The answers point out that this is unnecessary (agreed), but not why (or if) it's a bad idea.
It is a very common and perfectly correct practice to cascade FKs through multiple levels of a hierarchy modeling a "containment" or "belongs to" type relationship. But you don't just add FK columns, you use compound PKs on the child tables:
Area:
----------------
AreaId: (PK, bigint)
AreaName: (varchar)
Post:
----------------
AreaId: (PK,FK, bigint)
PostId: (PK, bigint)
Title: (varchar)
Text: (varchar)
Comment:
----------------
AreaId: (PK,FK, bigint)
PostId: (PK,FK, bigint)
CommentId: (PK, bigint)
Text: (varchar)
And each table has one FK, not two. So Comment has a two-column FK referencing Post.
The only real complaint against this model is that you have to join on multiple columns, but that's just complaining about having to type. This is most efficient model, as related rows are stored together in the PK index, and the PK index supports efficient lookups and traversals of the relationships. In the single-column key model, you must have secondary indexes supporting the FKs.
Modification is not necessary. Mostly people use multiple foreign keys to create easy queries and it is definitely not a bad idea according to me.
Related
I am developing a system where there are doctor , patient and diagnosis.
I made diagnosis a weak entity because without a doctor or a patient there will not be a diagnosis.
now I want to make a relationship called treatment between doctor and patient and diagnosis where a specific doctor will treat a specific patient that has a specific diagnosis.
how to make the relationship given that diagnosis is a weak entity that will not have it's own primary key.
I think your fundamental understanding of weak entities and primary keys is flawed.
You seem to think that because the weak entity table "includes" the primary keys of two other tables, that means it can't have a primary key of its own.
This is not the case. A Primary Key can be the combination of multiple columns, as long as that combination is Unique for all rows.
Based on what you describe you should have something like this:
Table Doctor
Primary Key: DoctorID
Table Patient
Primary Key: PatientID
Table Diagnosis
Primary Key: DoctorID, PatientID (or an Identity column to form an artificial PK)
Foreign Key: DoctorID References Table Doctor
Foreign Key: PatientID References Table Patient
So finally,
Table Treatment
Primary Key: DoctorID, PatientID (, Identity column of Table Diagnosis if you created one)
Foreign Key: DoctorID References Table Doctor
Foreign Key: PatientID References Table Patient
This is sufficient if a doctor can only diagnose each patient once, and also can only suggest one treatment per patient. If either of these combinations can have more than one instance, then you should add some third "Line Number" type column to the PK of the Diagnosis and/or Treatment table to include in the PK for that table and make it unique.
I am using access 2010 to do this.
I have created two tables and I would like to get it one to one and i don't seem to get it in to one to one relationship.
CREATE TABLE Person(
ID VARCHAR(1) UNIQUE,
Name VARCHAR(30),
PRIMARY KEY (ID)
);
CREATE TABLE Passport(
ID VARCHAR(1) UNIQUE,
Country VARCHAR(30),
PRIMARY KEY (ID),
FOREIGN KEY (ID) REFERENCES Person(ID)
);
From the little knowledge that I have, This should be a one to one relationship but it is a one to many. How do I get it one to one via ACCESS?
I have tried most things that I can find in books but with no success.
Please help.
You may simply be misled by the way relationships are displayed in the Relationships window. I ran your exact DDL and when I view the relationship in the Relationships window it looks like one-to-many...
...but when I right-click on the line joining the two tables and choose "Edit Relationship..." the dialog shows that it is actually one-to-one:
I beleive that in fact you created a one-to-one relationship as you wish.
the person id is unique
the passport id is unique
the passport id(unique) equals one person id(also unique).
So its one-to-one
However, it should be better design to have different ids for person and passport to have more clear design. Something like this:
CREATE TABLE Person(
PERSONID VARCHAR(1) UNIQUE,
Name VARCHAR(30),
PRIMARY KEY (PERSONID)
);
CREATE TABLE Passport(
PASSPORTID VARCHAR(1) UNIQUE,
Country VARCHAR(30),
PERSONID VARCHAR(1),
PRIMARY KEY (PASSPORTID),
FOREIGN KEY (PERSONID) REFERENCES Person(PERSONID)
);
This will also accomodate cases of persons with multiple passports.
I'm designing SQL Server tables with Natural Keys instead of a Surrogate Keys for the Primary Key. The problem I've run into is that it doesn't work well with the Audit table format that I've used with Surrogate Key tables in the past. Typically I'll create an audit table that has the same columns as the table being audited. A trigger on the table being audited writes a new row to the audit table that matches the state of the row before update or delete. To enforce integrity I use both the Surrogate Key and modified date columns as a composite PK for the table. If I don't use a Surrogate Key then I cannot track changes if one of the columns that make up the composite key changes.
Log table example with Surrogate Key:
LogId (PK)
LogType
Data
ModifedDate
ModifedBy
LogAudit Table for Log table with Surrogate Key:
LogId (PK)
LogType
Data
ModifedDate (PK)
ModifedBy
Log table example with Natural Key:
LogType (PK)
Data
ModifedDate (PK)
ModifedBy
LogAudit Table for Log table with Natural Key:
LogType
Data
ModifedDate
ModifedBy
How do you track changes for Natural Key Log table record in the Audit table if LogType or ModifiedDate change?
I think you misunderstood the basic concept here.
If it is true that {LogType, ModifedDate} is a natural key in the Log table (case 2), then it is also true that it is an alternate key (AK) (unique) in the first example.
So the Log table in the first example would look like this.
LogId (PK)
LogType (AK1.1)
Data
ModifedDate (AK1.2)
ModifedBy
So, for a given {LogID} the {LogType, ModifedDate} can not change, and vice versa.
But, this is not what you are trying to accomplish. The answer is probably that your Log table does not have "natural key" in the first place.
EDIT as per comments
As a rule-of-thumb, for creating a row-based audit table:
Copy the original table structure (columns).
Add ChangedAt (datetime) and ChangedBy columns to the table.
Add ChangedAt column to the original PK.
Add copy of PK columns to the table. This is to capture any PK changes.
Add FKs with ON UPDATE CASCADE, ON DELETE NO ACTION. This prevents hard-deletes, so use soft deletes.
Populate from an AFTER INSERT, UPDATE trigger on the original table.
Example 1
Table: {ID, SomeData} ; key: {ID}
audit table: {ID, SomeData, ChangedAt, ChangedBy, ID_CPY} ; key: {ID, ChangedAt}
Example 2
Table: {UserID, UserOrderNo, SomeData} ; key: {UserID, UserOrderNo}
audit table: {UserID, UserOrderNo, SomeData, ChangedAt, ChangedBy, UserID_CPY, UserOrderNo_CPY} ; key: {UserID, UserOrderNo, ChangedAt}
Example 3 (as per your description)
Table: {LogType, ModifedDate, SomeData} ; key: {LogType, ModifedDate}
audit table: {LogType, ModifedDate, SomeData, ChangedAt, ChangedBy, LogType_CPY, ModifedDate_CPY} ; key: {LogType, ModifedDate, ChangedAt}
Hmmmm, that natural key in particular is odd.
There is no restriction for you to have both sets of keys, natural and surrogate.
I would mix both tables i'd use LogID for PK and create a unique index for LogType+ModifiedDate, so that way you have a single field PK for joining tables (which i think is a good thing) and you have your Business/Natural Key (still unique just not Primary) for whatever you need it.
I'm building a database (for a class) to model a parts ordering application. "Suppliers" provide parts (different suppliers may each supply one or more parts that fulfill the same role, and every part fulfills exactly one role), "managers" decide which parts are going to be orderable (only one part that fulfills a given role can be orderable), and users can order the parts.
I'm currently in the E-R diagram drawing stage. I'm not sure how to model the parts, roles and orderables. I can represent each orderable/role as a (conceptual) "customer part" entity and create two relationships to the "supplier parts" entity:
That looks tremendously tacky with the "Created by Trial Version" all over it, but believe me, it's better than my chicken scratch handwriting.
However, there is one crucial constraint that would not be captured here. Imagine that you have two sets of supplier parts that fulfill one role each. Each set of parts (each role) would be represented by one customer part. However, the model does not guarantee that the customer part would correspond to a part that fulfills the correct role in the "orders" relationship.
I have also tried modelling it with a ternary relationship and an aggregation, but I still can't capture all the constraints.
My questions boils down to: I have parts, roles, and orderables. Roles and orderables map 1-1 and onto and can really be merged into a single entity. How do I represent that each part is associated with exactly one role, each role is associated with exactly one orderable and vice versa, and each orderable is associated with exactly one part that is also associated with the role corresponding to that orderable?
Thank you for any insights you may have.
I'm in a bit of a hurry, and I might have gotten lost in your requirements. (But +1 for stating them fairly clearly.) Let's tackle the easy stuff first. I'm mostly using natural keys here, because natural keys make it easier to see what's going on. The really important part for you, I think, is the overlapping foreign key constraints (near the end).
The easy stuff--tables for parts, suppliers, and roles.
create table test.parts (
part_num varchar(15) primary key
);
insert into test.parts values
('Part A'), ('Part B'), ('Part C');
-- "Suppliers" provide parts.
create table test.suppliers (
supplier_name varchar(35) primary key
);
insert into test.suppliers values
('Supplier A'), ('Supplier B'), ('Supplier C');
create table test.roles (
role_name varchar(15) primary key
);
insert into test.roles values
('Role 1'), ('Role 2'), ('Role 3');
One requirement: Every part fulfills exactly one role. (More about the UNIQUE constraint, and about using this table instead of simply adding a column to "parts" later.)
create table test.part_roles (
part_num varchar(15) primary key references test.parts (part_num),
role_name varchar(15) not null references test.roles (role_name),
unique (part_num, role_name)
);
insert into test.part_roles values
('Part A', 'Role 1'), ('Part B', 'Role 1'), ('Part C', 'Role 2');
Another requirement--each supplier may supply one or more parts that fulfill the same role. I think this simplifies to "Each supplier supplies multiple parts." (Storing the facts about which role a part belongs to is a different table's responsibility.)
create table test.supplied_parts (
supplier_name varchar(35) not null
references test.suppliers (supplier_name),
part_num varchar(15) not null references test.parts (part_num),
primary key (supplier_name, part_num)
);
insert into test.supplied_parts values
('Supplier A', 'Part A'),
('Supplier A', 'Part B'),
('Supplier A', 'Part C'),
('Supplier B', 'Part A'),
('Supplier B', 'Part B');
Another requirement--managers decide which parts are going to be orderable. (Handle the managers with GRANT and REVOKE.) Only one part that fulfills a given role can be orderable. (That implies either a primary key constraint or a unique constraint on role_name.) And you can't order a part unless someone supplies it. (So we'll need overlapping foreign key constraints.)
This is where the UNIQUE constraint on test.part_roles (part_num, role_name) I mentioned earlier comes in.
create table test.orderable_parts (
role_name varchar(15) primary key references test.roles,
part_num varchar(15) not null,
foreign key (part_num, role_name)
references test.part_roles (part_num, role_name),
supplier_name varchar(35) not null,
foreign key (supplier_name, part_num)
references test.supplied_parts (supplier_name, part_num)
);
insert into test.orderable_parts values
('Role 1', 'Part A', 'Supplier A'),
('Role 2', 'Part C', 'Supplier A');
I think you're probably better off with a separate table of part_roles. (Better than adding a column to parts, for example.) Suppliers usually supply more parts than you're interested in today, but businesses often want to plan ahead, gathering information about parts before they commit to using them (in your case, in a particular role).
suppliers
---------
PK supplier_id
parts -- 1-1 part to role
-----
PK part_id
FK role_id
stocks -- suppliers' parts
------
PK stock_id
FK supplier_id
FK part_id
roles
-----
PK role_id
managers
--------
PK manager_id
selections -- part selected by a manager for a role
----------
PK selection_id
FK manager_id
FK role_id
FK part_id
LEGEND: PK = Primary Key (assuming SERIAL PRIMARY KEY), FK = Foreign Key
Instead of the selections table you could also add FK part_id to roles.
I have a table named Books which contains 3 columns.
TableName: Books
Columns: BookId (PK), BookName, Book_Publisher_XRef_Id (FK), IsInternal
I have two tables that contains publisher information. Both these tables have different set of columns.
TableName: InternalPublishers
Columns: PublisherId (PK), PublisherName, ....
TableName: ExternalPublishers
Columns: PublisherId (PK), PublisherName, ....
I have a link table that contains information about which book belongs to which publisher. One book can have multple publishers.
TableName: Books_Publishers_XRef
Columns: Book_Publisher_XRef_Id (PK), PublisherId
If I want to create a Foreign Key constraint on PublisherId, I need to create sort of Composite Foreign Key constraint which I am not sure can be created.
So in this scenario, what is the best way to achieve FK on PublisherId in Books_Publishers_XRef table?
Break Books_Publishers_XRef table in 2 tables i.e. one for Internal Publishers and another one for External Publishers and have 2 columns in Books table for Books_Internal_Publishers_XRef and Books_External_Publishesr_XRef tables?
Don't create FK on Publisher_Id column and leave the design as it is?
Create composite FK by adding Publisher_Type_Id column in Books table and Books_Publishers_XRef table where if Publisher_Type_Id = 1, it belongs to Internal_Publishers table and Publisher_Type_Id = 2, it belongs to External_Publishers table ? (Not sure if this is possible)
Some other schema design?
Please advise.
Don't divide your data amongst two tables: InternalPublishers, ExternalPublishers. Create one table and have a bit field to determiner whether they are internal or external. Something like this:
create table Publisher
(
PublisherId int not null primary key clustered,
PublisherName varchar(100) not null,
IsInternal bit not null
)
go
That way you can easily create your foreign key reference. After all, you seem to have this same design for Books, keep that going to publishers.
Keep all common columns in the Publisher table.
Subtype tables have only columns specific to each one.