Integridad referencial con fk ciclica

07/12/2007 - 12:25 por Pablo Roca | Informe spam
Hola tengo una tabla de roles, que un registro puede ser padre de otros.
Está creada asi:

CREATE TABLE [dbo].[roles](
[pk_roles_id] [int] IDENTITY(1,1) NOT NULL,
[nombre] [varchar](30) NOT NULL CONSTRAINT [df_roles_nombre] DEFAULT (''),
[fk_pk_roles_id] [int] NULL,
CONSTRAINT [pk_roles_id] PRIMARY KEY CLUSTERED
(
[pk_roles_id] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY =
OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
) ON [PRIMARY]

GO
SET ANSI_PADDING OFF
GO
ALTER TABLE [dbo].[roles] WITH CHECK ADD CONSTRAINT [fk_roles_roles_id]
FOREIGN KEY([fk_pk_roles_id])
REFERENCES [dbo].[roles] ([pk_roles_id])
GO
ALTER TABLE [dbo].[roles] CHECK CONSTRAINT [fk_roles_roles_id]

Si me voy a modificar la relacion, no me deja modificar las reglas de
actualizazion ni eliminacion . Queria ponerlas en cascada.

Alguna pista en lo que tengo mal diseñado o que debo poner?


Saludos,

Pablo Roca
La Coruna - Spain
http://www.portalfox.com

Preguntas similare

Leer las respuestas

#16 Pablo Roca
07/12/2007 - 20:49 | Informe spam
Hola Carlos,

Estás estructurando un arbol. Y un arbol tiene dos
tipos de elementos, los nodos y los enlaces.
Estos dos tipos de entidades los tienes en una tabla.
La necesidad del null (o 0 por defecto) es un signo
de ello.



Efectivamente es un arbol, aunque en los requerimientos me piden que un
elemento padre solo tenga un hijo (cosa que aún no implementé), pero estoy
seguro que esto vá a cambiar y se permitiran varios hijos.

Considera esta estructura:



Bueno .. si esto cambia bastante las cosas, lo miro en detalle .. gracias


Saludos,

Pablo Roca
La Coruna - Spain
http://www.portalfox.com
Respuesta Responder a este mensaje
#17 Alejandro Mesa
07/12/2007 - 20:55 | Informe spam
En realidad podemos evitar la tabla temporal.

CREATE PROCEDURE dbo.DelTree
@pk_roles_id INT
AS
SET NOCOUNT ON

;WITH Tree
AS
(
SELECT [pk_roles_id], [fk_pk_roles_id]
FROM [dbo].[roles]
WHERE [pk_roles_id] = @pk_roles_id

UNION ALL

SELECT c.[pk_roles_id], c.[fk_pk_roles_id]
FROM dbo.roles AS c INNER JOIN Tree AS p ON c.[fk_pk_roles_id] =
p.[pk_roles_id]
)
DELETE r
FROM dbo.roles AS r INNER JOIN Tree AS t ON r.[pk_roles_id] = t.[pk_roles_id]
GO


AMB


"Alejandro Mesa" wrote:

Pablo,

Tambien puedes usar la logica en el triger, pero yo prefiero dejar la
restriccion de clave foranea para enforzar la integridad referencial.

USE tempdb
GO

CREATE TABLE [dbo].[roles](
[pk_roles_id] [int] IDENTITY(1,1) NOT NULL,
[nombre] [varchar](30) NOT NULL CONSTRAINT [df_roles_nombre] DEFAULT (''),
[fk_pk_roles_id] [int] NULL,
CONSTRAINT [pk_roles_id] PRIMARY KEY CLUSTERED
(
[pk_roles_id] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY =
OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
) ON [PRIMARY]
GO

SET ANSI_PADDING OFF
GO

ALTER TABLE [dbo].[roles] WITH CHECK ADD CONSTRAINT [fk_roles_roles_id]
FOREIGN KEY([fk_pk_roles_id])
REFERENCES [dbo].[roles] ([pk_roles_id])
GO

ALTER TABLE [dbo].[roles] CHECK CONSTRAINT [fk_roles_roles_id]
GO

INSERT INTO dbo.roles(nombre, fk_pk_roles_id) VALUES('Microsoft SQL Server',
NULL)
INSERT INTO dbo.roles(nombre, fk_pk_roles_id) VALUES('SS 6.5', 1)
INSERT INTO dbo.roles(nombre, fk_pk_roles_id) VALUES('SS 7', 1)
INSERT INTO dbo.roles(nombre, fk_pk_roles_id) VALUES('SS 2000', 1)
INSERT INTO dbo.roles(nombre, fk_pk_roles_id) VALUES('SS 2005', 1)
INSERT INTO dbo.roles(nombre, fk_pk_roles_id) VALUES('SS 2008', 1)
INSERT INTO dbo.roles(nombre, fk_pk_roles_id) VALUES('SS 2008 EE', 6)

SELECT * FROM dbo.roles
GO

CREATE PROCEDURE dbo.DelTree
@pk_roles_id INT
AS
SET NOCOUNT ON

CREATE TABLE #t([pk_roles_id] INT PRIMARY KEY, [fk_pk_roles_id] INT)

;WITH Tree
AS
(
SELECT [pk_roles_id], [fk_pk_roles_id]
FROM [dbo].[roles]
WHERE [pk_roles_id] = @pk_roles_id

UNION ALL

SELECT c.[pk_roles_id], c.[fk_pk_roles_id]
FROM dbo.roles AS c INNER JOIN Tree AS p ON c.[fk_pk_roles_id] =
p.[pk_roles_id]
)
INSERT INTO #t([pk_roles_id], [fk_pk_roles_id])
SELECT [pk_roles_id], [fk_pk_roles_id]
FROM [Tree]

DELETE r
FROM dbo.roles AS r INNER JOIN #t AS t ON r.[pk_roles_id] = t.[pk_roles_id]

IF OBJECT_ID('tempdb..#t') IS NOT NULL
DROP TABLE #t
GO

EXEC dbo.[DelTree] @pk_roles_id = 6
GO

SELECT *
FROM dbo.roles
GO

DROP PROCEDURE dbo.[DelTree]
GO

DROP TABLE [dbo].[roles]
GO


AMB


"Pablo Roca" wrote:

> Hola Alejandro
>
> CTE?
>
> Uso SQL Server 2005. Y como haria la llamada al proicedimniento almacenado?
> Me podrias indicarlo
>
>
> Saludos,
>
> Pablo Roca
> La Coruna - Spain
> http://www.portalfox.com
>
>
>
Respuesta Responder a este mensaje
#18 Pablo Roca
07/12/2007 - 21:06 | Informe spam
Fenomeno Alejandro!

Solo tiene el inconveniente de que no se puede mandar un DELETE directo a la
tabla roles .. sino que hay que pasar por el DelTree, pero eso no es ningun
problema, ya que lo llamo desde una clase de negocio centralizada.

Muchas gracias


Saludos,

Pablo Roca
La Coruna - Spain
http://www.portalfox.com
Respuesta Responder a este mensaje
#19 Carlos M. Calvelo
07/12/2007 - 21:20 | Informe spam
Hola Pablo,

On 7 dec, 20:49, "Pablo Roca" wrote:

Bueno .. si esto cambia bastante las cosas, lo miro en detalle .. gracias




Me gustaría añadir que:
- también se simplicarían mucho los constraints que estas
tratando de definir, y
- nodos pueden tener una 'vida' indenpendiente (y con sus
atributos) de que si están en el árbol o no.
Por ejemplo, son cosas muy distintas borrar enlaces o
borrar nodos.

Saludos,
Carlos
Respuesta Responder a este mensaje
#20 Pablo Roca
09/12/2007 - 19:22 | Informe spam
Bien .. ya tengo una implementación hecha. Gracias por las ideas.

Voy a postearlo en otro nuevo mensaje, para que se vea mejor


Saludos,

Pablo Roca
La Coruna - Spain
http://www.portalfox.com
email Siga el debate Respuesta Responder a este mensaje
Ads by Google
Help Hacer una pregunta AnteriorRespuesta Tengo una respuesta
Search Busqueda sugerida