【发布时间】:2014-06-28 12:00:14
【问题描述】:
您认为这可能是该模型的最佳方法
我们有一个类似的邻接列表模型
CREATE TABLE ITEM (id varchar(10), name varchar(50), parent varchar(10))
具有以下要求:“项目的父项必须是 id 的最接近的子字符串”
例如
id name parent
--------------------------
10 ItemA null
1000 ItemB 10
10005 ItemC 1000
此模型需要触发器来维护数据完整性
两个函数求帮助
CREATE FUNCTION fxAntecesors(@id varchar(10))
RETURNS TABLE AS
RETURN (
SELECT * FROM ITEM
WHERE @id LIKE id + '%' AND @id <> id
)
CREATE FUNCTION fxParent (@id varchar(10))
RETURNS varchar(10) AS
BEGIN
DECLARE @parent varchar(10)
SELECT @padre = MAX(id) FROM fxAntecesors(@id)
RETURN @parent
END
OnInsert 设置正确的父级
CREATE TRIGGER OnItemInsert ON ITEM
FOR INSERT AS
UPDATE ITEM
SET ITEM.parent = INSERTED.código
FROM ITEM, INSERTED
WHERE fxParent(ITEM.id) = INSERTED.id
OnDelete 指向父父节点
CREATE TRIGGER OnItemDelete ON ITEM
FOR DELETE AS
UPDATE ITEM
SET ITEM.parent = DELETED.parent
FROM ITEM, DELETED
WHERE ITEM.parent = DELETED.id
插入一个项目
CREATE PROCEDURE spItemInsert (@id varchar(10), @name varchar(50)) AS
INSERT INTO ITEM (id, name, parent) VALUES (@id, @name, fxParent(@id))
然后例如插入ItemD…
EXEC spItemInsert('100', 'ItemD')
表格如下
id name parent
-------------------------
10 ItemA null
100 ItemD 10 /// New Item Inserted ///
1000 ItemB 100 /// Parent updated on insert ItemD ///
10005 ItemC 1000
不知道有没有更好的模型?
对此有何正式规范?
感谢您的帮助,希望我解释得当
霍根,谢谢你的回答
但我认为使用这个解决方案我们会遇到同样的问题,而且可能会更复杂
请注意,Funky_id 与用户相关
CREATE FUNCTION fxAntecesors(@funkyid varchar(10))
RETURN TABLE AS
RETURN (SELECT * FROM ITEM_FUNKY_ID WHERE @funkyid LIKE funky_id + '%' AND @funkyid <> funky_id)
CREATE FUNCTION fxParentFunkyId (@funkyid varchar(10))
RETURNS varchar(10) AS
BEGIN
DECLARE @funkyparent varchar(10)
SELECT @funkyparent = MAX(funky_id) FROM fxAntecesors(@funkyid)
RETURN @funkyparent
END
CREATE FUNCTION fxParent(@funkyid varchar(10))
RETURN int
BEGIN
DECLARE @parent int
SELECT @parent = item_id FROM ITEM_FUNKY_ID WHERE funky_id = fxParentFunkyid(@funkyid)
RETURN @parent
END
CREATE FUNCTION fxFunkyId(@id int)
RETURN varchar(10)
BEGIN
DECLARE @funkyid varchar(10)
SELECT @funkyid = funky_id FROM ITEM_FUNKY_ID WHERE item_id = @id
RETURN @funkyid
END
CREATE PROCEDURE spItemInsert(@funkyid varchar(10), @name varchar(50)) AS
BEGIN
DECLARE @id int
SELECT @id = MAX(id) FROM ITEM
IF @id IS NULL
SET @id = 1
ELSE
SET @id = @id + 1
INSERT INTO ITEM (id, name, parent) VALUES (@id, @name, fxParent(@funkyid))
INSERT INTO ITEM_FUNKY_ID (item_id, funky_id) VALUES (@id, @funkyid)
END
CREATE TRIGGER OnInsertItemFunkyId ON ITEM_FUNKY_ID
FOR INSERT AS
UPDATE ITEM
SET ITEM.parent = INSERTED.item_id
FROM ITEM, INSERTED
WHERE fxParentFunkyId(fxFunkyId(ITEM.id)) = INSERTED.funky_id
CREATE TRIGGER OnItemDelete ON ITEM
FOR DELETE AS
UPDATE ITEM
SET ITEM.parent = DELETED.parent
FROM ITEM, DELETED
WHERE ITEM.parent = DELETED.id
在这种情况下
id name parent item_id funky_id
------------------------------------ -------------------------------
1 ItemA null 1 10
2 ItemB 1 2 1000
3 ItemC 2 3 10005
After insert new item…
exec spItemInsert '100', 'ItemD'
id name parent item_id funky_id
------------------------------------ -------------------------------
1 ItemA null 1 10
2 ItemB 4 -> //Updated on Trigger// 2 1000
3 ItemC 2 3 10005
4 ItemD 1 4 100
我认为两种解决方案之间没有太大区别,而第二种解决方案看起来更复杂
【问题讨论】:
-
对不起,我的英语不太好,我想知道是否有更好的方法来做到这一点
-
虽然您已经给出了一些要求(父是子字符串),但尚不清楚为什么需要这样做。在典型的关系数据库设计中,ID 不用作语义结构,而是表示关系。如果我有这个要求,我不会直接存储这些 ID,而是存储在相关表中。
-
"...但在相关表中" ?
-
这类似于标准的非规范化设计问题。 (en.wikipedia.org/wiki/Denormalization)。这就是为什么我一直问你为什么有这个要求——为什么你有这个要求是理解为什么你必须这样做的关键。可能会有更好的设计选择。
-
要求的原因是从用户的角度来看,他可以互换使用funkyid或name。对他来说,项目之间也存在子类或子组件的关系。甚至可以被视为一种助记方法,让用户知道一个项目是子项目还是其他后代。
标签: sql-server database hierarchical-data adjacency-list