أوراكل - الصفوف نوع الطبيعية على مستويات متعددة
سؤال
ولدي الجدول الذي يتكون من رقم السطر، وهو مستوى المسافة البادئة، والنص. ولست بحاجة لكتابة روتين إلى 'الطبيعية' فرز النص ضمن مستوى المسافة البادئة [أي طفل من مستوى المسافة البادئة أقل]. لدي خبرة محدودة مع إجراءات التحليل والاتصال عن طريق / قبل، ولكن من ما قرأت هنا وفي أماكن أخرى، يبدو أنها يمكن أن تكون وضعت لاستخدامها للمساعدة في قضيتي، ولكنني لا يمكن معرفة كيفية القيام بذلك.
CREATE TABLE t (ord NUMBER(5), indent NUMBER(3), text VARCHAR2(254));
INSERT INTO t (ord, indent, text) VALUES (10, 0, 'A');
INSERT INTO t (ord, indent, text) VALUES (20, 1, 'B');
INSERT INTO t (ord, indent, text) VALUES (30, 1, 'C');
INSERT INTO t (ord, indent, text) VALUES (40, 2, 'D');
INSERT INTO t (ord, indent, text) VALUES (50, 2, 'Z');
INSERT INTO t (ord, indent, text) VALUES (60, 2, 'E');
INSERT INTO t (ord, indent, text) VALUES (70, 1, 'F');
INSERT INTO t (ord, indent, text) VALUES (80, 2, 'H');
INSERT INTO t (ord, indent, text) VALUES (90, 2, 'G');
INSERT INTO t (ord, indent, text) VALUES (100, 3, 'J');
INSERT INTO t (ord, indent, text) VALUES (110, 3, 'H');
وهذا ما يلي:
SELECT ord, indent, LPAD(' ', indent, ' ') || text txt FROM t;
... العوائد:
ORD INDENT TXT
---------- ---------- ----------------------------------------------
10 0 A
20 1 B
30 1 C
40 2 D
50 2 Z
60 2 E
70 1 F
80 2 H
90 2 G
100 3 J
110 3 H
و11 الصفوف المحددة.
في حالة لقد محددة بالنسبة لك، ولست بحاجة روتيني لوضع ORD 60 = 50 وORD 50 = 60 [الوجه لهم] لE هو بعد D وقبل Z.
الشيء نفسه مع ORD 80 و 90 [مع 90 ليصل 100 و 110 مع ذلك لأنهم ينتمون إليها] و 100 و 110. وينبغي أن يكون الناتج النهائي:
ORD INDENT TXT
10 0 A
20 1 B
30 1 C
40 2 D
50 2 E
60 2 Z
70 1 F
80 2 G
90 3 H
100 3 J
110 2 H
والنتيجة هي أن كل مستوى المسافة البادئة يتم فرز أبجديا، ضمن مستوى المسافة البادئة، في حدود مستوى المسافة البادئة الأم.
المحلول
وهنا ما حصلت على العمل. أي فكرة عن كيفية كفاءة قد يكون على مجموعات أكبر. الجزء الصعب بالنسبة لي هو تحديد "الأم" لصف معين يعتمد فقط على النظام البادئة والأصلي.
WITH
a AS (
SELECT
t.*,
( SELECT MAX( ord )
FROM t t2
WHERE t2.ord < t.ord AND t2.indent = t.indent-1
) AS parent_ord
FROM
t
)
SELECT
ROWNUM*10 AS ord,
indent,
rpad( ' ', LEVEL-1, ' ' ) || text
FROM
a
CONNECT BY
PRIOR ord = parent_ord
START WITH
parent_ord IS NULL
ORDER SIBLINGS BY
text
نصائح أخرى
حسنا، هنا تذهب. الجزء الصعب في بنية البيانات الخاصة بك هو أن الأم ليست (صراحة) المعروف، حتى أن الجزء الأول من الاستعلام لا يفعل شيئا ولكن التعرف على الأم وفقا للقواعد (لكل عقدة، فإنه يحصل على كل subnodes مستوى واحد عميق، ووقف بمجرد identation أصغر أو يساوي عقدة البداية).
وبقية من السهل، في الأساس سوى بعض العودية مع الاتصال عن طريق للحصول على العناصر بالترتيب الذي تريده (إعادة ترقيم لهم حيوي).
WITH OrdWithParentInfo AS
(SELECT ID,
INDENT,
TEXT,
MIN(ParentID) ParentID
FROM (SELECT O.*,
CASE
WHEN (CONNECT_BY_ROOT ID = ID) THEN
NULL
ELSE
CONNECT_BY_ROOT ID
END ParentID
FROM (SELECT ROWNUM ID,
INDENT,
TEXT
FROM T
ORDER BY ORD) O
WHERE (INDENT = CONNECT_BY_ROOT INDENT + 1)
OR (CONNECT_BY_ROOT ID = ID)
CONNECT BY ((ID = PRIOR ID + 1) AND (INDENT > CONNECT_BY_ROOT INDENT)))
GROUP BY ID,
INDENT,
TEXT)
SELECT ROWNUM * 10 ORD, O.INDENT, O.TEXT
FROM OrdWithParentInfo O
START WITH O.ParentID IS NULL
CONNECT BY O.ParentID = PRIOR ID
ORDER SIBLINGS BY O.Text;