سؤال

ما هي الطرق التي تستخدمها لتصميم واسترجاع المعلومات الهرمية في قاعدة البيانات؟

هل كانت مفيدة؟

المحلول

تمت كتابة القطع النهائية حول هذا الموضوع بواسطة جو سيلكو، وقد قام بإعداد عدد منها في كتاب يسمى أشجار جو سيلكو والتسلسلات الهرمية في SQL for Smarties.

إنه يفضل تقنية تسمى الرسوم البيانية الموجهة.يمكن العثور على مقدمة لعمله حول هذا الموضوع هنا

نصائح أخرى

تعجبني خوارزمية اجتياز شجرة الطلب المسبق المعدلة.هذه التقنية تجعل من السهل جدًا الاستعلام عن الشجرة.

ولكن إليك قائمة بالروابط حول الموضوع التي قمت بنسخها من صفحة الويب الخاصة بالمساهمين في Zend Framework (PHP) (تم نشرها هناك بواسطة Laurent Melmoux في 05 يونيو 2007 الساعة 15:52).

العديد من الروابط لا تحتوي على لغة محددة:

هناك تمثيلان وخوارزميات رئيسية لتمثيل الهياكل الهرمية مع قواعد البيانات:

  • تُعرف المجموعة المتداخلة أيضًا باسم خوارزمية اجتياز شجرة الطلب المسبق المعدلة
  • نموذج القائمة المجاورة

تم شرحه جيدًا هنا:

فيما يلي بعض الروابط الأخرى التي قمت بجمعها:

نموذج القائمة المجاورة

مجموعة متداخلة

الرسوم البيانية

الطبقات :

مجموعات متداخلة من شجرة قاعدة البيانات Adodb

نموذج الزيارة ADOdb

الكمثرى::DB_NestedSet

شجرة إجاص

nstrees

ما هي أفضل طريقة لتمثيل التسلسل الهرمي في قاعدة بيانات SQL؟تقنية عامة ومحمولة؟

لنفترض أن التسلسل الهرمي مقروء في الغالب، ولكنه ليس ثابتًا تمامًا.لنفترض أنها شجرة العائلة.

وإليك كيفية عدم القيام بذلك:

create table person (
person_id integer autoincrement primary key,
name      varchar(255) not null,
dob       date,
mother    integer,
father    integer
);

وإدراج البيانات مثل هذا:

person_id   name      dob       mother father  
1           Pops      1900/1/1   null   null  
2           Grandma   1903/2/4   null   null  
3           Dad       1925/4/2   2      1  
4           Uncle Kev 1927/3/3   2      1
5           Cuz Dave  1953/7/8   null   4
6           Billy     1954/8/1   null   3

بدلاً من ذلك، قم بتقسيم العقد وعلاقاتك إلى جدولين.

create table person (
person_id integer autoincrement primary key,
name      varchar(255) not null,
dob       date
);

create table ancestor (
ancestor_id   integer,
descendant_id integer,
distance      integer
);

يتم إنشاء البيانات مثل هذا:

person_id   name      dob       
1           Pops      1900/1/1  
2           Grandma   1903/2/4   
3           Dad       1925/4/2   
4           Uncle Kev 1927/3/3
5           Cuz Dave  1953/7/8   
6           Billy     1954/8/1   

ancestor_id  descendant_id  distance
1            1              0
2            2              0
3            3              0
4            4              0
5            5              0
6            6              0
1            3              1
2            3              1
1            4              1
2            4              1
1            5              2
2            5              2
4            5              1
1            6              2
2            6              2
3            6              1

يمكنك الآن تشغيل استعلامات عشوائية لا تتضمن إعادة ربط الجدول بنفسه، وهو ما قد يحدث إذا كانت لديك العلاقة الوراثية في نفس صف العقدة.

من لديه أجداد؟

select * from person where person_id in 
    (select descendant_id from ancestor where distance=2);

كل أحفادك:

select * from person where person_id in 
    (select descendant_id from ancestor 
    where ancestor_id=1 and distance>0);

من هم الأعمام؟

select decendant_id uncle from ancestor 
    where distance=1 and ancestor_id in 
    (select ancestor_id from ancestor 
        where distance=2 and not exists
        (select ancestor_id from ancestor 
        where distance=1 and ancestor_id=uncle)
    )

يمكنك تجنب جميع مشاكل ضم الجدول إلى نفسه عبر الاستعلامات الفرعية، والقيد الشائع هو 16 فرعًا فرعيًا.

المشكلة هي أن الحفاظ على جدول الأسلاف أمر صعب نوعًا ما، ومن الأفضل القيام به من خلال إجراء مخزن.

يجب أن أختلف مع جوش.ماذا يحدث إذا كنت تستخدم هيكلًا هرميًا ضخمًا مثل تنظيم الشركة.يمكن للأشخاص الانضمام/الخروج من الشركة، وتغيير التسلسل الإداري، وما إلى ذلك...سيكون الحفاظ على "المسافة" مشكلة كبيرة وسيتعين عليك الاحتفاظ بجدولين من البيانات.

سيتيح لك هذا الاستعلام (SQL Server 2005 والإصدارات الأحدث) رؤية السطر الكامل لأي شخص وحساب مكانه في التسلسل الهرمي ولا يتطلب سوى جدول واحد لمعلومات المستخدم.يمكن تعديله للعثور على أي علاقة فرعية.

--Create table of dummy data
create table #person (
personID integer IDENTITY(1,1) NOT NULL,
name      varchar(255) not null,
dob       date,
father    integer
);

INSERT INTO #person(name,dob,father)Values('Pops','1900/1/1',NULL);  
INSERT INTO #person(name,dob,father)Values('Grandma','1903/2/4',null);
INSERT INTO #person(name,dob,father)Values('Dad','1925/4/2',1);
INSERT INTO #person(name,dob,father)Values('Uncle Kev','1927/3/3',1);
INSERT INTO #person(name,dob,father)Values('Cuz Dave','1953/7/8',4);
INSERT INTO #person(name,dob,father)Values('Billy','1954/8/1',3);

DECLARE @OldestPerson INT; 
SET @OldestPerson = 1; -- Set this value to the ID of the oldest person in the family

WITH PersonHierarchy (personID,Name,dob,father, HierarchyLevel) AS
(
   SELECT
      personID
      ,Name
      ,dob
      ,father,
      1 as HierarchyLevel
   FROM #person
   WHERE personID = @OldestPerson

   UNION ALL

   SELECT
    e.personID,
      e.Name,
      e.dob,
      e.father,
      eh.HierarchyLevel + 1 AS HierarchyLevel
   FROM #person e
      INNER JOIN PersonHierarchy eh ON
         e.father = eh.personID
)

SELECT *
FROM PersonHierarchy
ORDER BY HierarchyLevel, father;

DROP TABLE #person;

لعِلمِكَ:يقدم SQL Server 2008 نظامًا جديدًا معرف التسلسل الهرمي نوع البيانات لهذا النوع من الحالات.يمنحك التحكم في مكان وجود صفك في "الشجرة"، أفقيًا وعموديًا أيضًا.

وحي:يختار ...أبدا ب ...الاتصال عن طريق

لدى Oracle امتداد لـ SELECT يتيح استرجاعًا سهلاً يعتمد على الشجرة.ربما يحتوي SQL Server على بعض الامتدادات المماثلة؟

سوف يجتاز هذا الاستعلام جدولاً تم تخزين علاقة التداخل فيه الأبوين و طفل أعمدة.

select * from my_table
    start with parent = :TOP
    connect by prior child = parent;

http://www.adp-gmbh.ch/ora/sql/connect_by.html

أفضّل مزيجًا من التقنيات التي يستخدمها جوش ومارك هاريسون:

جدولان، أحدهما يحتوي على بيانات الشخص والآخر يحتوي على المعلومات الهرمية (person_id،parent_id [، mother_id]) إذا كان PK لهذا الجدول هو person_id، فلديك شجرة بسيطة بها أصل واحد فقط لكل عقدة (وهو أمر منطقي في في هذه الحالة، ولكن ليس في حالات أخرى مثل الحسابات المحاسبية)

يمكن تجاوز هذا الجدول الهرمي من خلال إجراءات متكررة أو إذا كانت قاعدة البيانات الخاصة بك تدعمها بجمل مثل SELECT...بواسطة بريور (أوراكل).

هناك احتمال آخر وهو إذا كنت تعرف الحد الأقصى لعمق بيانات التسلسل الهرمي الذي تريد الحفاظ عليه، فهو استخدام جدول واحد يحتوي على مجموعة من الأعمدة لكل مستوى من التسلسل الهرمي

واجهنا نفس المشكلة عندما قمنا بتنفيذ مكون شجرة لـ [فليكسيف] واستخدمت نهج نموذج شجرة المجموعة المتداخلة الذي ذكره ثاركون من ماي إس كيو إل مستندات.

بالإضافة إلى تسريع الأمور (بشكل كبير) استخدمنا أ انتشر النهج الذي يعني ببساطة أننا استخدمنا الحد الأقصى للقيمة الطويلة للحدود اليمنى ذات المستوى الأعلى والتي تسمح لنا بإدراج العقد ونقلها دون إعادة حساب جميع القيم اليسرى واليمنى.يتم حساب قيم اليسار واليمين عن طريق قسمة نطاق العقدة على 3 واستخدام داخلي الثالث كحدود للعقدة الجديدة.

يمكن رؤية مثال كود جافا هنا.

إذا كنت تستخدم SQL Server 2005 إذن هذا الرابط يشرح كيفية استرداد البيانات الهرمية.

يمكن أن تصبح تعبيرات الجدول الشائعة (CTEs) أصدقائك بمجرد أن تعتاد على استخدامها.

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top