Creo que necesita afirmaciones estándar SQL, que son (por desgracia) sin implementarse por DBMS reales.
Todas las respuestas están de acuerdo que hay tres tablas principales llamados TableA, TableB y TableC, cada uno con su propia columna ID:
TableA (A_ID PRIMARY KEY, ...)
TableB (B_ID PRIMARY KEY, ...)
TableC (C_ID PRIMARY KEY, ...)
no es claro por la descripción del problema de si una el único valor B puede tener múltiples entradas A principales. Está claro que una sola C puede tener múltiples entradas principales B. Si un B está ligado a una sola A, el diseño de la Tabla B puede ser revisado para:
TableB (B_ID, ..., A_ID REFERENCES TableA)
si un B puede estar asociada con varios diferentes Atléticos, a continuación, la conexión está mejor representado por una tabla de unión:
A_and_B (A_ID REFERENCES TableA,
B_ID REFERENCES TableB,
PRIMARY KEY (A_ID, B_ID)
)
Tampoco está claro a partir de la descripción si las C asociadas a una B deben ser iguales para cada A con la que B está asociada, o si diferentes A pueden hacer referencia a la misma B, y el conjunto de C asociado con B para A1 puede ser diferente del conjunto de C asociado con B para A2. (Por supuesto, si un solo B solo puede asociarse con un A, este problema es discutible.)
Para los fines de esta respuesta, supongo que cualquier B está asociado con una sola A, por lo tanto la estructura de TableB incluye A_ID como clave externa. Desde una sola C puede estar asociada con varios de B, la estructura relevante es una nueva tabla de unirse:
B_and_C (B_ID REFERENCES TableB,
C_ID REFERENCES TableC,
PRIMARY KEY (B_ID, C_ID)
)
Simplificar (omitiendo reglas sobre DEFERRABILITY e inmediatez) una afirmación se ve así:
CREATE ASSERTION assertion_name CHECK (<search_condition>)
Así Una vez que tenemos un conjunto de decisiones de diseño, podemos escribir una afirmación para validar los datos.Teniendo en cuenta las tablas Tabla A, TableB (con A_ID clave externa), y TableC B_and_C, el requisito es que el número de ocurrencias de un C_ID dada a través de un Una completa es 1.
CREATE ASSERTION only_one_instance_of_c_per_a CHECK
(
NOT EXISTS (
SELECT A_ID, COUNT(C_ID)
FROM TableB JOIN B_and_C USING (C_ID)
GROUP BY A_ID
HAVING COUNT(C_ID) > 1
)
)
[ Modificado: Creo que este es más preciso:
CREATE ASSERTION only_one_instance_of_c_per_a CHECK
(
NOT EXISTS (
SELECT A_ID, C_ID, COUNT(*)
FROM TableB JOIN B_and_C USING (C_ID)
GROUP BY A_ID, C_ID
HAVING COUNT(*) > 1
)
)
]
el conjunto de condiciones de combinación varía con otras reglas de cómo se conectan las tablas, pero la estructura general de restricción sigue siendo el mismo - no debe existir más de una r eferencia a un C_ID dado para un A_ID particular.
en los comentarios, notas meandmycode:
me da la sensación de que hay un defecto en mi diseño. Mi lógica del mundo real es que una 'B' siempre tiene al menos un niño 'C'. Esto no tiene sentido dado que 'B' debe existir antes de que su hijo pueda unirse. La base de datos permitiría adjuntar una 'B' a una 'A' sin tener al menos UN 'C' .. hijo, como tal voy a revisar 'B' para que tenga un campo que se refiera a su hijo primario 'C', además de tener una colección secundaria de 'C's' adicionales, pero ahora tengo una colección que también podría incluir la 'C' primaria especificada por la 'B', que sería ... incorrecta.
¿Hay un patrón db que infiera una regla de 'uno o más hijos', frente a cero o más?
Creo que tiene problemas con su modelo. Es difícil crear una B si ya debe existir una C que se refiera a la B recién creada, especialmente si las C solo deben referirse a las B existentes. La frase "pollo y huevo" viene a la mente. Entonces, normalmente, permites que B tenga cero o más C en un contexto como este.
Aún no se ha estipulado si TableB tiene una clave externa A_ID o si tiene una tabla de vinculación como A_and_B. Si tiene una clave externa, entonces presumiblemente no puede crear una B hasta que haya creado la A a la que se refiere.
No creo que incluir una ID de C en la tabla B sea una buena idea - hace que el procesamiento sea asimétrico (SQL más difícil). También significa que si necesita eliminar esa C, debe actualizar las cosas para que una de las otras C referencias se elimine de la tabla en la que se encuentra actualmente, y luego actualice el valor en el registro B. Eso es desordenado, ser amable al respecto.
Creo que necesita enmendar su pregunta para definir la estructura de la tabla real que está mirando, a lo largo de las líneas que se muestran en varias respuestas; puede usar puntos triples para representar otras columnas irrelevantes. La afirmación que sugerí probablemente debería implementarse como un tipo de desencadenante, que entra en las anotaciones específicas de DBMS.
partir de la descripción modificada de calzoncillos (A), presentaciones (B) y miembros (C), es evidente que una sola presentación se aplica a sólo un breve, por lo que las comunicaciones pueden tener una clave externa simple que identifica el resumen para el que es una presentación. Y un miembro solo puede colaborar en una presentación para un informe en particular. Habrá una tabla de 'submission_collaborators' con columnas para identificar el envío y el miembro, la combinación es la clave principal y cada columna es una clave externa.
Briefs(Brief_ID, ...)
Submissions(Submission_ID, Brief_ID REFERENCES Briefs, ...)
Members(Member_ID, ...)
Submission_Collaborators(Submission_ID REFERENCES Submissions,
Member_ID REFERENCES Members,
PRIMARY KEY (Submission_ID, Member_ID)
)
Por lo tanto, el requisito es que la siguiente consulta debe devolver ninguna fila:
SELECT s.brief_id, c.member_id, COUNT(*)
FROM submissions AS s JOIN submission_collaborators AS c
ON s.submission_id = c.submission_id
GROUP BY s.brief_id, c.member_id
HAVING COUNT(*) > 1
Esta es la misma consulta que I incrustado en la afirmación CREATE (segunda variante). Puede extraer información adicional (título breve, título de envío, nombre de miembro, varias fechas, etc.) también, pero el núcleo del problema es que la consulta mostrada no debe devolver datos.
+1 para querer que el DBMS haga cumplir la restricción independientemente de lo que hagan las aplicaciones. –
Estoy con Jonathan en esto, demasiadas personas solo consideran que la aplicación hace este trabajo y tienen malos datos como resultado. – HLGEM
Como lo demuestra mi respuesta, su escenario es bastante ofuscado y si puede modificarlo, debería hacerlo. La cantidad de sistemas que admiten CREATE ASSERTION es muy limitada. La declaración requerida para verificar las restricciones es compleja para usar en un disparador. –