B
BruceM
Jamie Collins said:We have a minor language issue. You seem to use "relationship" to mean
"Access Relationship with RI enforced", whereas I would use "FOREIGN
KEY" or perhaps "referenced table" and "referencing tables" in
context. FWIW I model a relationship using a table which I call a
"relationship table" which IIRC you call a "junction table".
I don't necessarily mean with RI enforced, but in most table relationships
that is the case. A join in a query may not have RI enforced. When I refer
to a table relationship I am using Access terminology to mean just what you
surmise.
Let's say tblStudent contains student information, and tblCourse contains
Course information. Each Student can be in many Courses, and each Course
contains many Students, so tblStudentCourse resolves the many-to-many
relationship. I call tblStudentCourse a junction table. A junction table
in my lexicon is this specific type of table.
So, I'm assuming you are referring to a FOREIGN KEY (my term). You are
correct that the NULL value here is a complication and one worth
avoiding by design. In Access/Jet, NULL and non-NULL values in the
referencing table must match exactly in the referencing table by
treating the NULL value as if it were an actual value; while this is
not strictly the correct way to handle the NULL value, it has utility
because the non-matching non-NULL values will cause the FK to bite,
also altering the NULL value to a non-NULL value in the referencing
table will result in the new value being CASCADEd to the referencing
table (assuming the ON UPDATE CASCADE referential action has been
specified for the FK). Contrast this with SQL Server which will not
test any FK rows involving the NULL value (i.e. the non-NULL values
may not match but the still FK will not bite as it would in Access/
Jet) and changing from the NULL value to a non-NULL value does not
CASCADE; arguably more correct but has less utility. I'm finding it
hard to describe long hand so here's an example (sorry its ANSI-92
Query Mode and includes the dreaded DDL):
CREATE TABLE Test1
(
col1 INTEGER NOT NULL,
col2 INTEGER, UNIQUE (col1, col2)
)
;
CREATE TABLE Test2
(
col1 INTEGER NOT NULL,
col2 INTEGER,
FOREIGN KEY (col1, col2)
REFERENCES Test1 (col1, col2)
ON DELETE CASCADE
ON UPDATE CASCADE
)
;
INSERT INTO Test1 (col1, col2)
VALUES (1, NULL)
;
INSERT INTO Test2 (col1, col2)
VALUES (1, NULL)
;
Consider this query:
SELECT *
FROM Test1 AS T1
INNER JOIN Test2 AS T2
ON T1.col1 = T2.col1
AND T1.col2 = T2.col2;
returns no rows because T1.col2=T2.col2, NULL=NULL, causes the row to
be removed from the resultset; put crudely, you can't compare the NULL
value to anything, even the NULL value.
I cannot get the CREATE TABLE stuff to work, even though I am using the
correct query mode. It expects a line number or a label or a few other
things. However, I think I see what you are getting at.
Now consider this:
DELETE FROM Test1;
causes the row in Test2 to be removed; Access/Jet successfully matched
NULL=NULL. Impressive or no? In SQL Server, the row would remain (not
orphaned because it was never considered to be referencing in the
first place).
That's one of the reasons why I used a NOT NULL end_date when I posted
the example i.e. to avoid this complexity ...but you did ask
Regardless, I would expect any designer to use (employee_number,
start_date) as the key for referencing tables.
I've tried to show you tables with a PRIMARY KEY but no logical key,
tables where a PRIMARY KEY cannot prevent duplicate data, and tables
where PRIMARY KEY is used for purposes of physical indexing rather
than logical keys.
I am lost with the difference between PRIMARY KEY and primary key, although
I suspect you are referring to the difference between a logical key (the
combination of fields that assures the record is unique) and a key that is
used in relationships with other tables (since a dozen fields may be needed
to construct a suitable logical key). However, as I have explained several
times I ensure by one means or another that records are unique. I have
asked how one places a unique constraint on a combination of fields without
making them into an Access PK. I don't know much about using a database
engine other than Jet, so the differences with a SQL engine are lost on me.
If you have answered my question about multi-field keys, I could not
understand your response as an answer to the question.
When you choose to use PRIMARY KEY, the choice of what you use it for
it arbitrary; feel free to omit a PRIMARY KEY but be ready for someone
to challenge you on it (e.g. document your reasons) because there is
this 'touch stone' in SQL that every table should have a primary key/
PRIMARY KEY -- I really don't know what variety they mean! Personally,
I think every table should have a both a primary key and a PRIMARY
KEY, basing their choice for the latter on good (documented) reasons.
For Access/Jet, clustering is IMO the best reason for using PRIMARY
KEY but I do know that many people value that bold text in the Access
'Relationships' diagram.
Final point on this subject: if someone is unaware of Access/Jet's
clustering behaviour, can they really make an informed decision about
PRIMARY KEY designation?
No idea. I know that my databases work, and it's not just dumb luck.
Do I need to tell you that your approach doesn't actually solve the
problem at hand? The aim is to prevent this (aircode):
INSERT INTO SUVs (VIN, etc)
SELECT VIN, etc)
FROM Vehicles
WHERE vehicle_type = 'Sedan';
I prevent it by limiting the choices the user can make once SUV has been
selected.
and similar updates that are contrary to the business rules.
What's your position on PRIMARY KEY? If I showed you this table:
CREATE TABLE Employees
(
employee_number INTEGER
);
and pointed out that all nine front end programs known to use the
database have front end code to trap duplicates and NULLs, would you
think it was a good idea to omit a NOT NULL unique constraint from the
SQL table?
I would tend not to edit employee information in those databases. When I
need to edit the information I go to the database that contains that
information. That is to say, I have one way to edit the information.
Anyhow, I *never, ever* argued in favor of allowing nulls in required
fields. If I am using the Employee table to populate a combo box list from
which a name is selected, there is no way to select a Null value. I can
require that the field be filled in before the rest of the record can be
completed by means of front end code to enforce the fact that the employee
ID is required in the table. Or I can use validation at the table level,
although that is not my usual choice.