SQL - كيفية تخزين التسلسلات الهرمية والتنقل فيها؟
-
09-06-2019 - |
سؤال
ما هي الطرق التي تستخدمها لتصميم واسترجاع المعلومات الهرمية في قاعدة البيانات؟
المحلول
تمت كتابة القطع النهائية حول هذا الموضوع بواسطة جو سيلكو، وقد قام بإعداد عدد منها في كتاب يسمى أشجار جو سيلكو والتسلسلات الهرمية في SQL for Smarties.
إنه يفضل تقنية تسمى الرسوم البيانية الموجهة.يمكن العثور على مقدمة لعمله حول هذا الموضوع هنا
نصائح أخرى
تعجبني خوارزمية اجتياز شجرة الطلب المسبق المعدلة.هذه التقنية تجعل من السهل جدًا الاستعلام عن الشجرة.
ولكن إليك قائمة بالروابط حول الموضوع التي قمت بنسخها من صفحة الويب الخاصة بالمساهمين في Zend Framework (PHP) (تم نشرها هناك بواسطة Laurent Melmoux في 05 يونيو 2007 الساعة 15:52).
العديد من الروابط لا تحتوي على لغة محددة:
هناك تمثيلان وخوارزميات رئيسية لتمثيل الهياكل الهرمية مع قواعد البيانات:
- تُعرف المجموعة المتداخلة أيضًا باسم خوارزمية اجتياز شجرة الطلب المسبق المعدلة
- نموذج القائمة المجاورة
تم شرحه جيدًا هنا:
- http://www.sitepoint.com/article/hierarchical-data-database
- إدارة البيانات الهرمية في MySQL
- http://www.evolt.org/article/Four_ways_to_work_with_hierarchical_data/17/4047/index.html
فيما يلي بعض الروابط الأخرى التي قمت بجمعها:
- http://en.wikipedia.org/wiki/Tree_%28data_structure%29
- http://en.wikipedia.org/wiki/Category:Trees_%28structure%29
نموذج القائمة المجاورة
مجموعة متداخلة
- http://www.sqlsummit.com/AdjacencyList.htm
- http://www.edutech.ch/contribution/nstrees/index.php
- http://www.phpriot.com/d/articles/php/application-design/nested-trees-1/
- http://www.dbmsmag.com/9604d06.html
- http://en.wikipedia.org/wiki/Tree_traversal
- http://www.cosc.canterbury.ac.nz/mukundan/dsal/BTree.html (التطبيق الصغير جافا montrant لو fonctionnement)
الرسوم البيانية
الطبقات :
مجموعات متداخلة من شجرة قاعدة البيانات Adodb
نموذج الزيارة ADOdb
الكمثرى::DB_NestedSet
- http://pear.php.net/package/DB_NestedSet
- السرة : https://www.entwickler.com/itr/kolumnen/psecom,id,26,nodeid,207.html
شجرة إجاص
- http://pear.php.net/package/Tree/download/0.3.0/
- http://www.phpkitchen.com/index.php?/archives/337-PEARTree-Tutorial.html
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;
أفضّل مزيجًا من التقنيات التي يستخدمها جوش ومارك هاريسون:
جدولان، أحدهما يحتوي على بيانات الشخص والآخر يحتوي على المعلومات الهرمية (person_id،parent_id [، mother_id]) إذا كان PK لهذا الجدول هو person_id، فلديك شجرة بسيطة بها أصل واحد فقط لكل عقدة (وهو أمر منطقي في في هذه الحالة، ولكن ليس في حالات أخرى مثل الحسابات المحاسبية)
يمكن تجاوز هذا الجدول الهرمي من خلال إجراءات متكررة أو إذا كانت قاعدة البيانات الخاصة بك تدعمها بجمل مثل SELECT...بواسطة بريور (أوراكل).
هناك احتمال آخر وهو إذا كنت تعرف الحد الأقصى لعمق بيانات التسلسل الهرمي الذي تريد الحفاظ عليه، فهو استخدام جدول واحد يحتوي على مجموعة من الأعمدة لكل مستوى من التسلسل الهرمي
واجهنا نفس المشكلة عندما قمنا بتنفيذ مكون شجرة لـ [فليكسيف] واستخدمت نهج نموذج شجرة المجموعة المتداخلة الذي ذكره ثاركون من ماي إس كيو إل مستندات.
بالإضافة إلى تسريع الأمور (بشكل كبير) استخدمنا أ انتشر النهج الذي يعني ببساطة أننا استخدمنا الحد الأقصى للقيمة الطويلة للحدود اليمنى ذات المستوى الأعلى والتي تسمح لنا بإدراج العقد ونقلها دون إعادة حساب جميع القيم اليسرى واليمنى.يتم حساب قيم اليسار واليمين عن طريق قسمة نطاق العقدة على 3 واستخدام داخلي الثالث كحدود للعقدة الجديدة.
يمكن رؤية مثال كود جافا هنا.
إذا كنت تستخدم SQL Server 2005 إذن هذا الرابط يشرح كيفية استرداد البيانات الهرمية.
يمكن أن تصبح تعبيرات الجدول الشائعة (CTEs) أصدقائك بمجرد أن تعتاد على استخدامها.