تسليم تسليم الساخم المسطح إلى قائمة بجميع المسارات

StackOverflow https://stackoverflow.com/questions/764497

سؤال

لدي جدول يخزن معلومات هرمية باستخدام نموذج قائمة المجاورة. (يستخدم مفتاح مرجعي مرجعي - مثال أدناه. قد ينظر هذا الجدول مألوف):

category_id name                 parent
----------- -------------------- -----------
1           ELECTRONICS          NULL
2           TELEVISIONS          1
3           TUBE                 2
4           LCD                  2
5           PLASMA               2
6           PORTABLE ELECTRONICS 1
7           MP3 PLAYERS          6
8           FLASH                7
9           CD PLAYERS           6
10          2 WAY RADIOS         6

ما هي أفضل طريقة ل "تسطيح" البيانات المذكورة أعلاه إلى شيء مثل هذا؟

category_id lvl1        lvl2        lvl3        lvl4
----------- ----------- ----------- ----------- -----------
1           1           NULL        NULL        NULL
2           1           2           NULL        NULL
6           1           6           NULL        NULL
3           1           2           3           NULL
4           1           2           4           NULL
5           1           2           5           NULL
7           1           6           7           NULL
9           1           6           9           NULL
10          1           6           10          NULL
8           1           6           7           8

كل صف هو واحد "مسار" من خلال التسلسل الهرمي، إلا أن هناك صف ل كل عقدة (ليس فقط كل عقدة ورقة). يمثل العمود فئة_ID العقدة الحالية وأعمدة "LVL" أسلافها. يجب أن تكون قيمة العقدة الحالية أيضا في أبعد عمود LVL الصحيح. ستتمثل القيمة في عمود LVL1 عقدة الجذر دائما، وسوف تمثل القيم في LVL2 دائما أحفاد LVL1، وهلم جرا.

إذا كان ذلك ممكنا، فستكون الطريقة لتوليد هذا الإخراج في SQL، وستعمل على التسلسلات الهرمية N-Tier.

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

المحلول

للقيام باستفسارات متعددة المستويات عبر قائمة مجاورة بسيطة تنطوي دائما على رد الفعل على الأيسر. من السهل إجراء جدول محاذاة الحق:

SELECT category.category_id,
    ancestor4.category_id AS lvl4,
    ancestor3.category_id AS lvl3,
    ancestor2.category_id AS lvl2,
    ancestor1.category_id AS lvl1
FROM categories AS category
    LEFT JOIN categories AS ancestor1 ON ancestor1.category_id=category.category_id
    LEFT JOIN categories AS ancestor2 ON ancestor2.category_id=ancestor1.parent
    LEFT JOIN categories AS ancestor3 ON ancestor3.category_id=ancestor2.parent
    LEFT JOIN categories AS ancestor4 ON ancestor4.category_id=ancestor3.parent;

إلى اليسار محاذاة مثل المثال الخاص بك هو أكثر صعبة بعض الشيء. هذا يتبادر إلى الذهن:

SELECT category.category_id,
    ancestor1.category_id AS lvl1,
    ancestor2.category_id AS lvl2,
    ancestor3.category_id AS lvl3,
    ancestor4.category_id AS lvl4
FROM categories AS category
    LEFT JOIN categories AS ancestor1 ON ancestor1.parent IS NULL
    LEFT JOIN categories AS ancestor2 ON ancestor1.category_id<>category.category_id AND ancestor2.parent=ancestor1.category_id
    LEFT JOIN categories AS ancestor3 ON ancestor2.category_id<>category.category_id AND ancestor3.parent=ancestor2.category_id
    LEFT JOIN categories AS ancestor4 ON ancestor3.category_id<>category.category_id AND ancestor4.parent=ancestor3.category_id
WHERE
    ancestor1.category_id=category.category_id OR
    ancestor2.category_id=category.category_id OR
    ancestor3.category_id=category.category_id OR
    ancestor4.category_id=category.category_id;

سوف تعمل من أجل التسلسل الهرمي N-tier.

آسف، استعلامات العمق التعسفي غير ممكن في نموذج القائمة المجاورة. إذا كنت تفعل هذا النوع من الاستعلام كثيرا، يجب عليك تغيير مخططك إلى أحد نماذج أخرى من تخزين المعلومات الهرمية: العلاقة المجاورة الكاملة (تخزين جميع العلاقات النمسية الجدولية) أو المسار المخصص أو مجموعات متداخلة.

إذا كانت الفئات لا تتحرك كثيرا (وهذا هو الحال عادة بالنسبة لمتجر مثل مثالك)، فسأفيل إلى مجموعات متداخلة.

نصائح أخرى

كما ذكر، لا يوجد لديه طريقة نظيفة لتنفيذ الجداول بأعداد متفاوتة ديناميكيا من الأعمدة. الحلول الوحيدان الذي استخدمته من قبل: 1. ينضم ذاتي عدد ثابت، وإعطاء عدد ثابت من الأعمدة (حسب BOBINCE) 2. إنشاء النتائج كسلسلة في عمود واحد

الشخص الثاني يبدو غروتيا في البداية؛ معرفات تخزين كسلسلة؟! ولكن عندما يتم تنسيق الإخراج ك XML أو شيء ما، لا يبدو أن الناس يمركون كثيرا.

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


أنا عالق هنا على شاشة 10 بوصة دون إمكانية الوصول إلى SQL، لذلك لا يمكنني إعطاء رمز اختبار، ولكن الطريقة الأساسية ستكون الاستفادة من العودية بطريقة ما؛
- وظيفة العدد العسكري يمكن أن تفعل هذا
- MS SQL يمكن القيام بذلك باستخدام عبارة متكررة (أكثر كفاءة)

وظيفة العددية (شيء مثل):

CREATE FUNCTION getGraphWalk(@child_id INT)
RETURNS VARCHAR(4000)
AS
BEGIN

  DECLARE @graph VARCHAR(4000)

  -- This step assumes each child only has one parent
  SELECT
    @graph = dbo.getGraphWalk(parent_id)
  FROM
    mapping_table
  WHERE
    category_id = @child_id
    AND parent_id IS NOT NULL

  IF (@graph  IS NULL)
    SET @graph = CAST(@child_id AS VARCHAR(16))
  ELSE
    SET @graph = @graph + ',' + CAST(@child_id AS VARCHAR(16))

  RETURN @graph

END


SELECT
  category_id                         AS [category_id],
  dbo.getGraphWalk(category_id)       AS [graph_path]
FROM
  mapping_table
ORDER BY
  category_id

أنا لم أستخدم متكررة مع فترة من الوقت، لكنني سأقدم بناء الجملة، رغم أنني لا أملك SQL هنا لاختبار أي شيء :)

العودية مع

WITH
  result (
    category_id,
    graph_path
  )
AS
(
  SELECT
    category_id,
    CAST(category_id AS VARCHAR(4000))
  FROM
    mapping_table
  WHERE
    parent_id IS NULL

  UNION ALL

  SELECT
    mapping_table.category_id,
    CAST(result.graph_path + ',' + CAST(mapping_table.category_id AS VARCHAR(16)) AS VARCHAR(4000))
  FROM
    result
  INNER JOIN
    mapping_table
      ON result.category_id = mapping_table.parent_id
)

SELECT
  *
FROM
  result
ORDER BY
  category_id


تحرير - إخراج كلاهما هو نفسه:

1   '1'
2   '1,2'
3   '1,2,3'
4   '1,2,4'
5   '1,2,5'
6   '1,6'
7   '1,6,7'
8   '1,6,7,8'
9   '1,6,9'

يتضمن عبور شجرة عمق تعسفي عموما رمز إجرائي متكرر، إلا إذا كنت تستخدم السمات الخاصة لبعض DBMS.

في Oracle، تسمح لك Connect By Fre بتجاوز الشجرة في العمق أولا، إذا كنت تستخدم قائمة المجاورة، كما فعلت هنا.

إذا كنت تستخدم مجموعات متداخلة، فإن رقم التسلسل الأيسر سوف يوفر لك الأمر لزيارة العقد.

في الواقع يمكن القيام به مع SQL الديناميكي داخل إجراء المتاجر. ثم تصبح تقتصر على ما يمكن القيام به Sith الإجراء المخزن. من الواضح أنها تصبح تحديا لإعادة تنفيذ النتائج إلى جدول مؤقت لا يعرف عدد الأعمدة التي تتوقعها. ومع ذلك، إذا كان الهدف هو الإخراج إلى صفحة ويب أو UI أخرى، فقد يستحق الجهد ...

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