Considera lo siguiente:
entity User
{
autoincrement uid;
string(20) name;
int privilegeLevel;
}
entity DirectLoginUser
{
inherits User;
string(20) username;
string(16) passwordHash;
}
entity OpenIdUser
{
inherits User;
//Whatever attributes OpenID needs... I don't know; this is hypothetical
}
Los diferentes tipos de usuarios (usuarios de inicio de sesión directo y usuarios de OpenID) muestran una relación IS-A; a saber, que ambos tipos de usuarios son usuarios. Ahora, hay varias formas en que esto se puede representar en un RDBMS:
Un camino
CREATE TABLE Users
(
uid INTEGER AUTO_INCREMENT NOT NULL,
name VARCHAR(20) NOT NULL,
privlegeLevel INTEGER NOT NULL,
type ENUM("DirectLogin", "OpenID") NOT NULL,
username VARCHAR(20) NULL,
passwordHash VARCHAR(20) NULL,
//OpenID Attributes
PRIMARY_KEY(uid)
)
Camino dos
CREATE TABLE Users
(
uid INTEGER AUTO_INCREMENT NOT NULL,
name VARCHAR(20) NOT NULL,
privilegeLevel INTEGER NOT NULL,
type ENUM("DirectLogin", "OpenID") NOT NULL,
PRIMARY_KEY(uid)
)
CREATE TABLE DirectLogins
(
uid INTEGER NOT_NULL,
username VARCHAR(20) NOT NULL,
passwordHash VARCHAR(20) NOT NULL,
PRIMARY_KEY(uid),
FORIGEN_KEY (uid) REFERENCES Users.uid
)
CREATE TABLE OpenIDLogins
(
uid INTEGER NOT_NULL,
// ...
PRIMARY_KEY(uid),
FORIGEN_KEY (uid) REFERENCES Users.uid
)
Camino tres
CREATE TABLE DirectLoginUsers
(
uid INTEGER AUTO_INCREMENT NOT NULL,
name VARCHAR(20) NOT NULL,
privlegeLevel INTEGER NOT NULL,
username VARCHAR(20) NOT NULL,
passwordHash VARCHAR(20) NOT NULL,
PRIMARY_KEY(uid)
)
CREATE TABLE OpenIDUsers
(
uid INTEGER AUTO_INCREMENT NOT NULL,
name VARCHAR(20) NOT NULL,
privlegeLevel INTEGER NOT NULL,
//OpenID Attributes
PRIMARY_KEY(uid)
)
Estoy casi seguro de que la tercera forma es la equivocada, porque no es posible hacer una unión simple contra usuarios en otra parte de la base de datos.
Sin embargo, mi ejemplo del mundo real no es un usuario con diferentes inicios de sesión; Estoy interesado en cómo modelar esta relación en el caso general.
database-design
Billy ONeal
fuente
fuente
Respuestas:
La segunda forma es la correcta.
Su clase base obtiene una tabla, y luego las clases secundarias obtienen sus propias tablas con solo los campos adicionales que introducen, además de referencias de claves externas a la tabla base.
Como Joel sugirió en sus comentarios sobre esta respuesta, puede garantizar que un usuario tendrá un inicio de sesión directo o un inicio de sesión de OpenID, pero no ambos (y posiblemente tampoco ninguno) agregando una columna de tipo a cada tabla de subtipo que devuelve la clave a la tabla raíz. La columna de tipo en cada tabla de subtipo está restringida a tener un solo valor que representa el tipo de esa tabla. Debido a que esta columna tiene una clave externa para la tabla raíz, solo una fila de subtipo puede vincularse a la misma fila raíz a la vez.
Por ejemplo, el DDL de MySQL se vería así:
(En otras plataformas, usaría una
CHECK
restricción en lugar deENUM
). MySQL admite claves foráneas compuestas, por lo que esto debería funcionar para usted.La primera forma es válida, aunque está desperdiciando espacio en esas
NULL
columnas habilitadas porque su uso depende del tipo de usuario. La ventaja es que si elige expandir qué tipos de tipos de usuario almacenar y esos tipos no requieren columnas adicionales, simplemente puede expandir el dominio de suENUM
y usar la misma tabla.La tercera forma obliga a las consultas que hacen referencia a los usuarios a comparar ambas tablas. Esto también evita que haga referencia a una sola tabla de usuarios a través de una clave externa.
fuente
UNION
, o habría sugerido una vista indexada con un índice único en comparación con elUNION ALL
deuid
las dos tablas.)type
columna a cada tabla de subtipo que está restringida porCHECK
restricción para tener exactamente un valor (el tipo de esa tabla). Luego, convertimos las claves externas de la subtabla para la supertabla en compuestas en ambasuid
ytype
. Eso es ingeniosoSerían nombrados
y todos tienen sus usos legítimos y son compatibles con algunas bibliotecas. Tienes que averiguar cuál se ajusta mejor.
Tener varias tablas haría que la gestión de datos se adaptara más al código de su aplicación, pero reduciría la cantidad de espacio no utilizado.
fuente