【问题标题】:Adjacency list model and substring foreign key邻接表模型和子串外键
【发布时间】: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


【解决方案1】:

我发表了评论。

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

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

但是,我将在 cmets 中回答您的问题并解释我所说的“在相关表中”是什么意思,这里是一个如何将此信息放入相关表中的示例。

首先,您的表格应如下所示:

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 上是不受欢迎的。请选择您的平台。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2011-05-09
    • 1970-01-01
    • 2020-11-13
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多