邻接列表模型和子串外键

时间:2014-06-28 12:00:14

标签: sql-server database hierarchical-data adjacency-list

您认为这可能是此模型的最佳方法

我们有一个邻接列表模型,如

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

我认为两种解决方案之间没有太大区别,第二种解决方案看起来更复杂

1 个答案:

答案 0 :(得分:0)

我发表了评论。

虽然您已经给出了一些要求(父级是子字符串),但不清楚为什么需要这样做。在典型的关系数据库设计中,除了表示关系之外,ID不用作语义结构。如果我有这个要求,我不会直接存储这些ID,而是存储在相关的表中。

我原来评论的要点是要理解“为什么?”。为什么要以这种方式设置ID。我能想到的唯一的事情是排序和一些其他组件的要求。在这两种情况下,我都会有其他设计建议。

但是,我会在评论中回答您的问题并解释“在相关表格中”的含义,以下是如何将此信息放在相关表格中的示例。

首先,你的表应该是这样的:

CREATE TABLE ITEM (id integer, name varchar(50), parent integer)

然后创建相关表格:

CREATE TABLE ITEM_FUNKY_ID (item_id integer, funky_id varchar(10))

在此表中,您为ITEM表中的每个ID添加一行。然后在第二列中添加varchar id。任何“修复”(例如,当您删除项目时)都将在此表中完成,并且只更改funky_id列。

还有一点 - 您将问题标记为。通常,这在SO上是不受欢迎的。请选择您的平台。