I have a table called ProjectList. I have two other tables called Estimates and Orders.
The Primary keys for Estimates and Orders and are foreign keys in ProjectList. A ProjectList record is created first, then Estimate records are created and then and an Order record.
How would I create foreign key constraints in ProjectList for Estimates and Orders without violating the Order foreign key constraints?
The only thing I can think of is create an empty Orders record when an Estimate is created. Not sure if that is an elegant solution.
Well, the root problem here is a logical error: your DB model claims that it is possible to have a project estimate and an order before the project exists.
To illustrate the point, a logical model should look somehow like this:
-- Project PRO exists.
--
project {PRO}
PK {PRO}
-- Project estimate number EST_NO of project PRO exists.
--
estimate {PRO, EST_NO}
PK {PRO, EST_NO}
FK {PRO} REFERENCES project {PRO}
-- Project order number ORD_NO of project PRO exists.
--
order {PRO, ORD_NO}
PK {PRO, ORD_NO}
FK {PRO} REFERENCES project {PRO}
Note how you can not create an estimate or an order before the project. If for some reason you prefer single column IDs, then the example can be modified as:
-- Project PRO_ID exists.
--
project {PRO_ID}
PK {PRO_ID}
-- Project estimate identified by EST_ID
-- for project PRO_ID exists.
--
estimate {EST_ID, PRO_ID}
PK {EST_ID}
FK {PRO_ID} REFERENCES project {PRO_ID}
-- Project order identified by ORD_ID
-- for project PRO_ID exists.
--
order {ORD_ID, PRO_ID}
PK {ORD_ID
FK {PRO_ID} REFERENCES project {PRO_ID}
So, FKs in your example are reversed. Database design is all about logic, it stems from it. Although you may find a way to band-aid around the perceived technical problem using some SQL trickery, the underlying logical error (bug) will remain.
Note:
All attributes (columns) NOT NULL
PK = Primary Key
AK = Alternate Key (Unique)
FK = Foreign Key
Related
I'm having a really, really strange issue with postgres. I'm trying to generate GUIDs for business objects in my database, and I'm using a new schema for this. I've done this with several business objects already; the code I'm using here has been tested and has worked in other scenarios.
Here's the definition for the new table:
CREATE TABLE guid.public_obj
(
guid uuid NOT NULL DEFAULT uuid_generate_v4(),
id integer NOT NULL,
CONSTRAINT obj_guid_pkey PRIMARY KEY (guid),
CONSTRAINT obj_id_fkey FOREIGN KEY (id)
REFERENCES obj (obj_id)
ON UPDATE CASCADE ON DELETE CASCADE
)
However when I try to backfill this using the following code, I get a SQL state 23503 claiming that I'm violating the foreign key constraint.
INSERT INTO guid.public_obj (guid, id)
SELECT uuid_generate_v4(), o.obj_id
FROM obj o;
ERROR: insert or update on table "public_obj" violates foreign key constraint "obj_id_fkey"
SQL state: 23503
Detail: Key (id)=(-2) is not present in table "obj".
However, if I do a SELECT on the source table, the value is definitely present:
SELECT uuid_generate_v4(), o.obj_id
FROM obj o
WHERE obj_id = -2;
"0f218286-5b55-4836-8d70-54cfb117d836";-2
I'm baffled as to why postgres might think I'm violating the fkey constraint when I'm pulling the value directly out of the corresponding table. The only constraint on obj_id in the source table definition is that it's the primary key. It's defined as a serial; the select returns it as an integer. Please help!
Okay, apparently the reason this is failing is because unbeknownst to me the table (which, I stress, does not contain many elements) is partitioned. If I do a SELECT COUNT(*) FROM obj; it returns 348, but if I do a SELECT COUNT(*) FROM ONLY obj; it returns 44. Thus, there are two problems: first, some of the data in the table has not been partitioned correctly (there exists unpartitioned data in the parent table), and second, the data I'm interested in is split out across multiple child tables and the fkey constraint on the parent table fails because the data isn't actually in the parent table. (As a note, this is not my architecture; I'm having to work with something that's been around for quite some time.)
The partitioning is by implicit type (there are three partitions, each of which contains rows relating to a specific subtype of obj) and I think the eventual solution is going to be creating GUID tables for each of the subtypes. I'm going to have to handle the stuff that's actually in the obj table probably by selecting it into a temp table, dropping the rows from the obj table, then reinserting them so that they can be partitioned properly.
Here's the part of my ERD:
OrderID from the Orders table relates to the OrderID/ProductID primary key in the Order Details table. I don't think primary keys can relate to other primary keys, but I'm not sure how else to relate the tables. Make them both primary and foreign keys?
You seem to be missing some basic ideas behind PKs (primary keys), UNIQUE NOT NULL, FKs (foreign keys), superkeys, CKs (candidate keys), simple vs composite PKs/UNIQUEs and ERDs (Entity-Relationship Diagrams). From this recent answer:
PKs & FKs are erroneously called "relationships" in some methods and
products. Application relationships are represented by tables. (Base
tables and query results.) PKs & FKs are constraints: they tell the
DBMS that only certain situations can arise, so it can notice when you
make certain errors. They are not relationships, they are statements
true in & of every database state and application situation. You do
not need to know constraints to update and query a
database.
Just declare per what is true of your relationships/tables:
a PK or UNIQUE NOT NULL declaration says that every subrow value in a column set is unique. Ie that the column set is a superkey. (A PK is just a distinguished UNIQUE NOT NULL.)
a FK declaration says that a column list subrow value in referencing columns must also be in referenced superkey columns.
I don't think primary keys can relate to other primary keys,
They can: A primary key can be a FK referencing another superkey. (You seem to be using "relates to" to mean "is referenced by a FK in").
But note: Here you have two PKs Order OrderID & Product ProductID referenced as FKs in ("relating to") OrderLine. But they are each FKs referencing ("relating from"?) part of OrderLine composite PK {OrderID,ProductID}.
but I'm not sure how else to relate the tables.
First declare CKs (candidate keys): Superkeys that don't contain smaller superkeys. Then declare FKs. (Then for a SQL DBMS declare any undeclared superkeys referenced by FKs.)
Make them both primary and foreign keys?
Yes: They are PKs in Order & Product. They are FKs in OrderLine referencing Order & Product. And the PK of OrderLine happens to be {OrderID,ProductID}.
PS In your style of ERD the lines are (apparently) merely FKs, with all the entities and relationships having tables. In some forms of ERDs there are entity tables, labeled lines representing relationships/tables (each end involving a FK) and unlabeled lines representing just FKs. When you see a diagram style always be sure you understand how to determine what icons represent relationships/tables and just what those relationships are in terms of the application. (Not just their cardinalities.)
I don't think primary keys can relate to other primary keys, but I'm
not sure how else to relate the tables.
This is perfectly fine, and it is quite commonly done.
What you are doing is referred to as a Compound Key. Compound keys don't have to link to other tables, but they can.
The relationships indicated by your diagram are not relationships between two primary keys. It looks like the attribute OrderID in Order Details references the Orders table. The attribute ProductID in Order Details references the Products table. These are sometimes called identifying relationships because the referencing attributes happen to be part of a key.
Relationships between keys are perfectly valid but that isn't what is shown in your diagram.
What is shown on the diagram is a FK relationship and is common
Orders and Products have PK so OrderID and ProductID are unique
So now you have OrderDetails so an order can have multiple products
The FKs assure valid values for OrderID and ProductID
In addition you should add a composite PK of OrderID, ProductID on OrderDetails
This way you don't have duplicate ProductID for the same OrderID
You have Quantity for dealing with multiple
UnitPrice is a catch
If you want to have multiple unit price for a ProductID in an OrderID then you would not be able to declare OrderID, ProductID as a PK
I would avoid going down that path if you can
Some of the answers conflate the concepts of relationships and foreign key constraints, as do many (most?) ER diagramming tools.
For clarification, there are 6 relationships (in the sense that Chen used the word) visible in the diagram:
Orders.OrderID, Orders.CustomerID
Orders.OrderID, Orders.ShipperID
Orders.OrderID, Orders.PaymentTypeID
OrderDetails.OrderID, OrderDetails.ProductID
Products.ProductID, Products.ProductTypeID
Products.ProductID, Products.LocationID
and 7 foreign key constraints (I assumed some table names):
OrderDetails.OrderID ⊆ Orders.OrderID
OrderDetails.ProductID ⊆ Products.ProductID
Orders.CustomerID ⊆ Customers.CustomerID
Orders.ShipperID ⊆ Shippers.ShipperID
Orders.PaymentTypeID ⊆ PaymentTypes.PaymentTypeID
Products.ProductTypeID ⊆ ProductTypes.ProductTypeID
Products.LocationID ⊆ Locations.LocationID
They aren't the same thing at all.
I am having a bit of trouble creating a foreign key in my DB. Here is a paraphrased model of what my tables look like:
NOTE
* (PK) NOTE_ID BIGINT
* TITLE VARCHAR(200)
* DATE DATETIME
* SERIES_ID BIGINT
SERIES
* (PK) SERIES_ID BIGINT
* TITLE VARCHAR(200)
* DESCR VARCHAR(1000)
I am trying to create a "has a" relationship between NOTE and SERIES by SERIES_ID. I thought that setting up a foreign key between the two tables by SERIES_ID would be the solution, but when I attempt to create it I get the following error:
ERROR: There are no primary or candidate keys in the referenced table 'dbo.SERIES' that match the referencing column list in the
foreign key 'FK_SERIES_NOTE'. Could not create constraint
I'm using the web database manager that comes with the GoDaddy SQL Server I set up, so I'm not sure what the underlying query it's trying to use or I would post it.
At the end of the day, this is all to create a relationship so that the NHibernate mappings for my Note object will contain a one-to-one relationship to a Series object. I may not even be trying to tackle this the correct way with the foreign key, though.
Am I going about this the correct way?
EDIT:
In an attempt to pair down the tables to a more simple example, I removed what I thought to be several non-critical columns. However, I ended up leaving a field that was actually a part of the composite primary key on the series table. So, because I was trying to assign the foreign key to only one part of the composite key, it was not allowing me to do so.
In the end, I have taken another look at the structure of my table and found that I don't actually need the other piece of the composite key - and after removing, the assignment of the foreign key works great now.
If you can, you may try running the following statement in a query analyzer and see the resulting error message (I guess #Damien_The_Unbeliever is right ) :
ALTER TABLE NOTE ADD CONSTRAINT FK_SERIES_NOTE
FOREIGN KEY (SERIES_ID) REFERENCES SERIES(SERIES_ID)
--ON DELETE CASCADE
-- uncomment the preceding line if you want a delete on a serie
-- to automatically delete all notes on this serie
Hope this will help
I had a lot of trouble implementing the technique described in an Alexander Kuznetsov article. Basically, the article describes a way to create a FK between one table and alternate tables, and still maintain full constraints on those relationship.
Here's part of Alexander's code:
CREATE TABLE dbo.Vehicles(
ID INT NOT NULL,
[Type] VARCHAR(5) NOT NULL,
CONSTRAINT Vehicles_PK PRIMARY KEY(ID),
CONSTRAINT Vehicles_UNQ_ID_Type UNIQUE(ID, [Type]),
CONSTRAINT Vehicles_CHK_ValidTypes CHECK([Type] IN ('Car', 'Truck'))
)
CREATE TABLE dbo.Cars(ID INT NOT NULL,
[Type] AS CAST('Car' AS VARCHAR(5)) PERSISTED,
OtherData VARCHAR(10) NULL,
CONSTRAINT Cars_PK PRIMARY KEY(ID),
CONSTRAINT Cars_FK_Vehicles FOREIGN KEY(ID, [Type])
REFERENCES dbo.Vehicles(ID, [Type])
)
I finally got it working after errors and confirmed bugs. But when I generate my EF models from the new schema, it is missing a relationship between two of my tables.
The problem is that, in order to have a FK on two columns, there must be an index or unique constraint on both those columns. However, in my case, I also have another table with a FK to a single column in the base table (Vehicles, in Alexander's code).
Since you cannot have more than one PK in a table, this means I cannot have a FK to a PK on both sides. The PK can be for one or two columns, and the other FK will need to reference the non-PK unique constraint.
Unfortunately, Entity Framework will only create relationships for you when there is a FK to a PK. That's the problem. Can someone who understand DB design better than I spot any other alternatives here?
Note: I realize some will see the obvious fix as simply modifying the model to manually add the additional relationship. Unfortunately, we are using a database project and are constantly using automated systems to regenerate the project and model from an updated database. So manual steps are really not practical.
You can't have more than one PK, but you can have more than one unique constraint, and in SQL Server you can create a foreign key constraint that references a unique constraint (one or multiple columns). Here is an example of two tables that roughly look like your model.
CREATE TABLE dbo.Vehicles
(
VehicleID INT PRIMARY KEY,
[Type] VARCHAR(5) NOT NULL UNIQUE,
CONSTRAINT u1 UNIQUE(VehicleID, [Type])
);
CREATE TABLE dbo.Cars
(
CarID INT PRIMARY KEY,
VehicleID INT NOT NULL
FOREIGN KEY REFERENCES dbo.Vehicles(VehicleID),
[Type] VARCHAR(5) NOT NULL
FOREIGN KEY REFERENCES dbo.Vehicles([Type]),
CONSTRAINT fk1 FOREIGN KEY (VehicleID, [Type])
REFERENCES dbo.Vehicles(VehicleID, [Type])
);
Note that Cars has three foreign keys: one points to the PK of vehicles (VehicleID), one points to the unique constraint on Vehicles([Type]), and one points to the multi-column unique constraint on Vehicles(VehicleID, [Type]). I realize this is not equivalent to what you are trying to do but should demonstrate that SQL Server, at least, is capable of doing everything you seem to want to do (I'm having a hard time concluding what you're actually because you keep swapping concepts between what Alex did, what you're trying to do but failing, and what you've done successfully).
Are you saying that EF will not recognize a foreign key that references a unique constraint? If so, does that affect constraints that have more than one column, or all unique constraints? If this is the case, that's a shame, because it is certainly supported in SQL Server. Seems like this would either be a bug or an intentional omission (given that the standard doesn't strictly allow FKs against unique constraints). I wonder if there are any bugs reported on Connect?
I have no idea how to force EF to recognize it, but I do know that just about all the people I know who use database projects end up performing pre- or post-deployment modifications and these can be relatively automated.
I need to define a one-to-one relationship, and can't seem to find the proper way of doing it in SQL Server.
Why a one-to-one relationship you ask?
I am using WCF as a DAL (Linq) and I have a table containing a BLOB column. The BLOB hardly ever changes and it would be a waste of bandwidth to transfer it across every time a query is made.
I had a look at this solution, and though it seems like a great idea, I can just see Linq having a little hissy fit when trying to implement this approach.
Any ideas?
One-to-one is actually frequently used in super-type/subtype relationship. In the child table, the primary key also serves as the foreign key to the parent table. Here is an example:
CREATE TABLE Organization
(
ID int PRIMARY KEY,
Name varchar(200),
Address varchar(200),
Phone varchar(12)
)
GO
CREATE TABLE Customer
(
ID int PRIMARY KEY,
AccountManager varchar(100)
)
GO
ALTER TABLE Customer
ADD FOREIGN KEY (ID) REFERENCES Organization(ID)
ON DELETE CASCADE
ON UPDATE CASCADE
GO
Why not make the foreign key of each table unique?
there is no such thing as an explicit one-to-one relationship.
But, by the fact that tbl1.id and tbl2.id are primary keys and tbl2.id is a foreign key referenceing tbl1.id, you have created an implicit 1:0..1 relationship.
Put 1:1 related items into the same row in the same table. That's where "relation" in "relational database" comes from - related things go into the same row.
If you want to reduce size of data traveling over the wire consider either projecting only the needed columns:
SELECT c1, c2, c3 FROM t1
or create a view that only projects relevant columns and use that view when needed:
CREATE VIEW V1 AS SELECT c1, c2, c3 FROM t1
SELECT * FROM t1
UPDATE v1 SET c1=5 WHERE c2=7
Note that BLOBs are stored off-row in SQL Server so you are not saving much disk IO by vertically-partitioning your data. If these were non-BLOB columns you may benefit form vertical partitioning as you described because you will do less disk IO to scan the base table.
How about this. Link the primary key in the first table to the primary key in the second table.
Tab1.ID (PK) <-> Tab2.ID (PK)
My problem was I have a 2 stage process with mandatory fields in both. The whole process could be classed as one episode (put in the same table) but there is an initial stage and final stage.
In my opinion, a better solution for not reading the BLOB with the LINQ query would be to create a view on the table that contains all the column except for the BLOB ones.
You can then create an EF entity based on the view.