I have tables with relationships like the following.
CREATE TABLE DocumentType
(
ID uniqueidentifier primary key,
...
)
GO
CREATE TABLE LinkedDoc
(
ID uniqueidentifier ROWGUIDCOL NOT NULL,
DocumentTypeID uniqueidentifier NOT NULL,
...,
CONSTRAINT [PK_LinkedDoc]
PRIMARY KEY CLUSTERED (ID, DocumentTypeID)
)
GO
ALTER TABLE LinkedDoc
ADD CONSTRAINT FK_DocumentType_LinkedDoc
FOREIGN KEY(DocumentTypeID) REFERENCES DocumentType (ID)
GO
CREATE TABLE SomeOtherTable
(
ID uniqueidentifier primary key,
...
)
CREATE TABLE ManyToMany
(
ID uniqueidentifier primary key,
LinkedDocID uniqueidentifier,
DocumentTypeID uniqueidentifier
SomeOtherTableID uniqueidentifier,
CONSTRAINT IX_ManyToMany UNIQUE (DocumentTypeID, SomeOtherTable)
)
GO
ALTER TABLE ManyToMany WITH CHECK
ADD CONSTRAINT FK_SomeOtherTable_ManyToMany
FOREIGN KEY (SomeOtherTableID) REFERENCES SomeOtherTable (ID)
GO
ALTER TABLE ManyToMany WITH CHECK
ADD CONSTRAINT FK_LinkedDoc_ManyToMany
FOREIGN KEY (LinkedDocID, DocumentTypeID) REFERENCES LinkedDoc (ID, DocumentTypeID)
GO
I omitted some details not relevant to my question. My goal was to build the tables so that each unique entity in the SomeOtherTable
cannot be linked to more than one LinkedDoc
with a given doc type. This is achieved above via the IX_ManyToMany
constraint.
While it works, this solution isn't sitting well with me, and I'd like to change it now before I load data into the system. The main point of concern is IX_ManyToMany
has a partial dependency on the tables primary key. Additionally ID
in LinkedDoc
is a ROWGUIDCOL
meaning my pk for the table is not minimal.
Is there a better alternative? I'd be open to refactor my tables, but I would like to avoid db triggers and functions because at that point I feel like I'm putting business logic in the db. I prefer to keep BL in my API, where it's source controlled and easier to maintain.
I found this Constraint for a many-to-many relationship table - both the related records need to reference the same dependent record? The first answer is similar to my solution. The second uses a db function which I'm willing to consider, but would like to see if it can be done by modifying the schema. Although, rather than using the function solution I may opt to simply allow the db to violate my requirement and then handle it in the API.
1条答案
按热度按时间hfsqlsce1#
This is indeed the standard way to go about this:
Note also that
ManyToMany
does not actually need a separateID
column, the PK can be made up of just(LinkedDocID, SomeOtherTableID)
.The main point of concern is IX_ManyToMany has a partial dependency on the tables primary key. Additionally ID in LinkedDoc is a ROWGUIDCOL meaning my pk for the table is not minimal.
I'm not sure why you are using
ROWGUIDCOL
, which is really for replication scenarios, but it's not relevant. Yes, it is sort-of a dependency, but you need to think ofLinkedDoc
as having two keys: a PK onID
and a secondaryUNIQUE
on(ID, DocumentTypeID)
, and that extra column is just part of its secondary key which needs to go into the foreign table.So the definition should be
Note I have used a unique index rather than a unique constraint, as this allows you to add
INCLUDE
, and still works as a FK target.The other option is to enforce this using an indexed view. This is unikely to be more efficient though, unless you need the indexed view anyway.
Then create a joined view containing the
DocumentTypeID
And index it