একটি ফ্ল্যাট টেবিলকে গাছের মধ্যে পার্স করার সবচেয়ে দক্ষ / মার্জিত উপায় কী?


517

ধরে নিন আপনার কাছে একটি সমতল টেবিল রয়েছে যাতে একটি অর্ডারযুক্ত গাছের স্তরক্রম সংরক্ষণ করা হয়:

Id   Name         ParentId   Order
 1   'Node 1'            0      10
 2   'Node 1.1'          1      10
 3   'Node 2'            0      20
 4   'Node 1.1.1'        2      10
 5   'Node 2.1'          3      10
 6   'Node 1.2'          1      20

এখানে একটি চিত্র আছে, যেখানে আমাদের রয়েছে [id] Name। রুট নোড 0 কল্পিত।

                       [0] মূল
                          / 
              [1] নোড 1 [3] নোড 2
              / \ \
    [2] নোড 1.1 [6] নোড 1.2 [5] নোড 2.1
          /          
 [4] নোড 1.1.1

এইচটিএমএলে (বা সেই বিষয়ে পাঠ্য) সঠিকভাবে অর্ডার করা, সঠিকভাবে ইন্টেন্টেড ট্রি হিসাবে আউটপুট দেওয়ার ক্ষেত্রে আপনি কোন নমনীয় পদ্ধতির ব্যবহার করবেন?

ধরে নিলেন আপনার কাছে কেবলমাত্র বেসিক ডেটা স্ট্রাকচার (অ্যারে এবং হ্যাশম্যাপস), পিতামাতাদের / সন্তানের উল্লেখগুলির সাথে কোনও অভিনব অবজেক্ট নেই, কোনও ওআরএম নেই, কোনও ফ্রেমওয়ার্ক নেই, কেবল আপনার দুটি হাত। সারণীটি ফলাফলের সেট হিসাবে উপস্থাপিত হয়, যা এলোমেলোভাবে প্রবেশ করা যায়।

সিউডো কোড বা সরল ইংরাজী ঠিক আছে, এটি নিখুঁত একটি ধারণাগত প্রশ্ন।

বোনাস প্রশ্ন: আরডিবিএমএসে গাছের কাঠামো সংরক্ষণের মতো মৌলিকভাবে আরও ভাল উপায় আছে কি?


সম্পাদনা এবং সংস্থানসমূহ

একজন মন্তব্যকারীর ( মার্ক বেসির ) প্রশ্নের উত্তর দেওয়ার জন্য : একটি রুট নোড প্রয়োজনীয় নয়, কারণ এটি কখনই প্রদর্শিত হবে না। প্যারেন্টআইডি = 0 হ'ল "এগুলি শীর্ষ স্তরের" প্রকাশ করার কনভেনশন। অর্ডার কলামটি নির্ধারণ করে যে একই পিতামাতার সাথে নোডগুলি কীভাবে বাছাই করা হবে।

আমি যে "ফলাফল সেট" এর কথা বলেছিলাম তা হ্যাশম্যাপের অ্যারে হিসাবে চিত্রায়িত করা যেতে পারে (সেই পরিভাষায় থাকার জন্য)। আমার উদাহরণটি ইতিমধ্যে সেখানে থাকার বোঝানো হয়েছিল। কিছু উত্তর অতিরিক্ত মাইল যায় এবং এটি প্রথমে নির্মাণ করে তবে ঠিক আছে।

গাছটি নির্বিচারে গভীর হতে পারে। প্রতিটি নোডে এন বাচ্চা থাকতে পারে। যদিও আমি মনে মনে "লক্ষ লক্ষ এন্ট্রি" গাছ রাখি নি।

কোনও কিছুর উপর নির্ভর করার জন্য নোড নামকরণের ('নোড 1.1.1') এর পছন্দটি ভুল করবেন না। নোডগুলিকে সমানভাবে 'ফ্র্যাঙ্ক' বা 'বব' বলা যেতে পারে, নামকরণের কোনও কাঠামো বোঝানো হয়নি, এটি কেবল এটি পাঠযোগ্য।

আমি আমার নিজস্ব সমাধান পোস্ট করেছি যাতে আপনি লোকেরা এটি টুকরো টানতে পারেন।


2
"পিতামাতাদের / সন্তানের উল্লেখগুলির সাথে কোনও অভিনব অবজেক্ট নেই" - কেন নয়? .AddChild (), .getParent () পদ্ধতির সাহায্যে একটি বেসিক নোড অবজেক্ট তৈরি করা আপনাকে নোডের সম্পর্কটিকে বেশ ভালভাবে মডেল করতে দেয়।
ম্যাট বি

2
এটি কি নিয়মিত (এন বাচ্চারা যেখানে এন হতে পারে> 2) গাছ বা বাইনারি ট্রি (নোডে 0, 1 বা 2 বাচ্চা থাকতে পারে)?
বিকিমেল

যেহেতু আপনি একটি হ্যাশম্যাপের সাহায্যে একটি নোড ডেটা কাঠামো বাস্তবায়ন করতে পারেন, তাই এখানে আরও কোনও বাস্তব বাধা নেই, কেবল আরও কাজ just
সোভান্তে

... এবং আপনি ঠিক তাই করেছেন।
সোভান্তে

উত্তর:


451

এখন যে মাইএসকিউএল 8.0 পুনরাবৃত্ত অনুসন্ধানগুলি সমর্থন করে , আমরা বলতে পারি যে সমস্ত জনপ্রিয় এসকিউএল ডাটাবেসগুলি স্ট্যান্ডার্ড সিনট্যাক্সে পুনরাবৃত্ত অনুসন্ধানগুলি সমর্থন করে

WITH RECURSIVE MyTree AS (
    SELECT * FROM MyTable WHERE ParentId IS NULL
    UNION ALL
    SELECT m.* FROM MyTABLE AS m JOIN MyTree AS t ON m.ParentId = t.Id
)
SELECT * FROM MyTree;

আমি আমার উপস্থাপনায় মাইএসকিউএল 8.0 এ পুনরাবৃত্ত অনুসন্ধানগুলি পরীক্ষা করেছি 2017 সালে রিকার্সিভ কোয়েরি থ্রোডাউন

নীচে আমার মূল উত্তরটি ২০০৮ সাল থেকে:


রিলেশনাল ডাটাবেসে গাছ-কাঠামোগত ডেটা সংরক্ষণ করার বিভিন্ন উপায় রয়েছে। আপনি আপনার উদাহরণে যা দেখান তা দুটি পদ্ধতি ব্যবহার করে:

  • সংলগ্ন তালিকা ("পিতামাতার" কলাম) এবং
  • পাথ গণনা (আপনার নাম কলামে বিন্দুযুক্ত সংখ্যা)।

অন্য সমাধানটিকে নেস্টেড সেটস বলা হয় এবং এটি একই টেবিলেও সংরক্ষণ করা যায়। এই নকশাগুলির বিষয়ে আরও অনেক তথ্যের জন্য জো সেলকো রচিত " এসকিউএল এর জন্য এসকিউএল এ গাছ এবং হায়ারারচিগুলি " পড়ুন ।

গাছের কাঠামোগত ডেটা সংরক্ষণ করার জন্য আমি সাধারণত ক্লোজার টেবিল (ওরফে "অ্যাডজেসেন্সি রিলেশন") নামে একটি ডিজাইন পছন্দ করি । এটির জন্য অন্য টেবিলের প্রয়োজন, তবে গাছগুলি জিজ্ঞাসা করা খুব সহজ।

আমি এসকিউএল এবং পিএইচপি এবং আমার বই এসকিউএল অ্যান্টিপ্যাটার্নস: হিজরাইজিকাল ডেটাগুলির মডেলগুলির জন্য আমার উপস্থাপনায় ক্লোজার টেবিলটি কভার করি : ডেটাবেস প্রোগ্রামিংয়ের ক্ষতিগুলি এড়ানো

CREATE TABLE ClosureTable (
  ancestor_id   INT NOT NULL REFERENCES FlatTable(id),
  descendant_id INT NOT NULL REFERENCES FlatTable(id),
  PRIMARY KEY (ancestor_id, descendant_id)
);

সমাপ্তি টেবিলের সমস্ত পাথ সংরক্ষণ করুন, যেখানে একটি নোড থেকে অন্য নোডে সরাসরি বংশ রয়েছে। প্রতিটি নোডের নিজের উল্লেখের জন্য একটি সারি অন্তর্ভুক্ত করুন। উদাহরণস্বরূপ, ডেটা সেট ব্যবহার করে আপনি আপনার প্রশ্নে দেখিয়েছেন:

INSERT INTO ClosureTable (ancestor_id, descendant_id) VALUES
  (1,1), (1,2), (1,4), (1,6),
  (2,2), (2,4),
  (3,3), (3,5),
  (4,4),
  (5,5),
  (6,6);

এখন আপনি নোড 1 এ শুরু করে একটি গাছ পেতে পারেন:

SELECT f.* 
FROM FlatTable f 
  JOIN ClosureTable a ON (f.id = a.descendant_id)
WHERE a.ancestor_id = 1;

আউটপুট (মাইএসকিউএল ক্লায়েন্টে) নিম্নলিখিতগুলির মতো দেখাচ্ছে:

+----+
| id |
+----+
|  1 | 
|  2 | 
|  4 | 
|  6 | 
+----+

অন্য কথায়, নোড 3 এবং 5 বাদ দেওয়া হয়েছে, কারণ তারা নোড 1 থেকে নেমে না, একটি পৃথক শ্রেণিবিন্যাসের অংশ।


পুনরায়: তাত্ক্ষণিক শিশুদের (বা তাত্ক্ষণিক অভিভাবক) সম্পর্কে ই-সন্তুষ্টের মন্তব্য। তাত্ক্ষণিক শিশু বা পিতামাতার (বা অন্য কোনও দূরত্ব) এর জন্য বিশেষভাবে জিজ্ঞাসা করা সহজ করার জন্য আপনি " path_length" কলামে একটি যুক্ত করতে পারেন ClosureTable

INSERT INTO ClosureTable (ancestor_id, descendant_id, path_length) VALUES
  (1,1,0), (1,2,1), (1,4,2), (1,6,1),
  (2,2,0), (2,4,1),
  (3,3,0), (3,5,1),
  (4,4,0),
  (5,5,0),
  (6,6,0);

তারপরে প্রদত্ত নোডের তাত্ক্ষণিক শিশুদের জিজ্ঞাসা করার জন্য আপনি আপনার অনুসন্ধানে একটি পদ যুক্ত করতে পারেন। এই উত্তরপুরূষ যার দ্বারা path_length1।

SELECT f.* 
FROM FlatTable f 
  JOIN ClosureTable a ON (f.id = a.descendant_id)
WHERE a.ancestor_id = 1
  AND path_length = 1;

+----+
| id |
+----+
|  2 | 
|  6 | 
+----+

@ আশরাফের কাছ থেকে মন্তব্য করুন: "পুরো গাছটিকে [নাম দিয়ে] বাছাই করার পদ্ধতি কীভাবে?"

নোড 1 এর বংশধর যে সমস্ত নোডগুলি ফেরত দেওয়ার জন্য এখানে একটি উদাহরণ ক্যোয়ারী রয়েছে, ফ্ল্যাট টেবলে তাদের সাথে যুক্ত হোন যেমন নোডের অন্যান্য বৈশিষ্ট্য যেমন name, এবং নাম অনুসারে বাছাই করুন।

SELECT f.name
FROM FlatTable f 
JOIN ClosureTable a ON (f.id = a.descendant_id)
WHERE a.ancestor_id = 1
ORDER BY f.name;

@ নেট থেকে মন্তব্য পুনরায়:

SELECT f.name, GROUP_CONCAT(b.ancestor_id order by b.path_length desc) AS breadcrumbs
FROM FlatTable f 
JOIN ClosureTable a ON (f.id = a.descendant_id) 
JOIN ClosureTable b ON (b.descendant_id = a.descendant_id) 
WHERE a.ancestor_id = 1 
GROUP BY a.descendant_id 
ORDER BY f.name

+------------+-------------+
| name       | breadcrumbs |
+------------+-------------+
| Node 1     | 1           |
| Node 1.1   | 1,2         |
| Node 1.1.1 | 1,2,4       |
| Node 1.2   | 1,6         |
+------------+-------------+

একজন ব্যবহারকারী আজ একটি সম্পাদনার পরামর্শ দিয়েছেন। এসও মডারেটররা সম্পাদনাটি অনুমোদন করেছে, তবে আমি এটিকে বিপরীত করছি।

সম্পাদনাটি পরামর্শ দিয়েছে যে উপরের শেষ প্রশ্নের মধ্যে অর্ডার বাই দ্বারা হওয়া উচিত ORDER BY b.path_length, f.name, সম্ভবত এটি নিশ্চিত করার জন্য যে ক্রমটি ক্রমবিন্যাসের সাথে মিলছে। তবে এটি কাজ করে না, কারণ এটি "নোড ১.১.১" এর পরে "নোড ১.২" অর্ডার করবে।

যদি আপনি ক্রমবিন্যাসকে বুদ্ধিমান উপায়ে মেলাতে চান তবে এটি সম্ভব, তবে কেবল পথের দৈর্ঘ্য অনুসারে অর্ডার দিয়ে নয়। উদাহরণস্বরূপ, মাইএসকিউএল বন্ধের সারণি শ্রেণিবদ্ধ ডাটাবেসের আমার উত্তর দেখুন - সঠিক ক্রমে কীভাবে তথ্য টানতে হবে


6
এটি খুব মার্জিত, আপনাকে ধন্যবাদ। বোনাস পয়েন্ট পুরষ্কার। ;-) আমি যদিও একটি ছোট ত্রুটি দেখতে পাচ্ছি - এটি সন্তানের সম্পর্কটি স্পষ্টভাবে এবং অন্তর্নিহিতভাবে সঞ্চয় করে রাখে, গাছের কাঠামোতে এমনকি একটি ছোট স্থান পরিবর্তন করার জন্য আপনাকে অনেক সাবধানতা অবলম্বন করতে হবে।
টমলক

16
সত্য, কোনও ডাটাবেসে গাছ-কাঠামো সংরক্ষণের প্রতিটি পদ্ধতির জন্য গাছ তৈরি বা আপডেট করার সময়, বা গাছ এবং সাবট্রিজ অনুসন্ধানের সময় কিছু কাজ প্রয়োজন। আপনি সহজ হতে চান তার উপর ভিত্তি করে নকশা চয়ন করুন: লেখা বা পড়া।
বিল কারভিন

2
@ বাফার, আপনি শ্রেণিবিন্যাসের জন্য সমস্ত সারি তৈরি করার সাথে সাথে অসংগতি তৈরি করার সুযোগ রয়েছে। অ্যাডজেসেন্সি তালিকায় ( parent_id) প্রতিটি পিতা-মাতার সন্তানের সম্পর্ক প্রকাশ করার জন্য কেবল একটি সারি রয়েছে, তবে বন্ধ সারণীতে অনেকগুলি রয়েছে।
বিল কারভিন

1
@ বিলকারউইন আরও একটি বিষয়, যে কোনও নোডের একাধিক পাথ সহ গ্রাফের জন্য ক্লোজার টেবিলগুলি উপযুক্ত (যেমন কোনও বিভাগের স্তরক্রম যেখানে কোনও পাত বা নন-পাতার নোড একাধিক প্যারেন্টের অন্তর্ভুক্ত থাকতে পারে)
ব্যবহারকারী

2
@ রেজা, যাতে আপনি একটি নতুন শিশু নোড যুক্ত করেন তবে আপনি (1) এর সমস্ত বংশধরদের জন্য জিজ্ঞাসা করতে পারেন এবং সেগুলিই নতুন সন্তানের পূর্বপুরুষ।
বিল কারভিন

58

যদি আপনি নেস্টেড সেটগুলি ব্যবহার করেন (কখনও কখনও সংশোধিত প্রাক-অর্ডার ট্রি ট্রভারসাল হিসাবে পরিচিত) আপনি গাছের ক্রমে পুরো গাছের কাঠামো বা এর কোনও সাবট্রিকে একটি একক ক্যোয়ারী সহ সন্ধান করতে পারেন, প্রবেশের মূল্যে আরও ব্যয়বহুল হওয়াতে আপনার প্রয়োজন হিসাবে কলামগুলি পরিচালনা করুন যা আপনার গাছের কাঠামোর মধ্য দিয়ে একটি ক্রম পথ বর্ণনা করে।

জন্য জ্যাঙ্গো-mptt , আমি এই মত একটি কাঠামো ব্যবহৃত:

আইডি প্যারেন্ট_আইডি ট্রি_আইডি স্তর লেফট আরআরজিটি
- --------- ------- ----- --- ----
 1 নাল 1 0 1 14
 2 1 1 1 2 7
 3 2 1 2 3 4
 4 2 1 2 5 6
 5 1 1 1 8 13
 6 5 1 2 9 10
 7 5 1 2 11 12

যা এমন গাছটিকে বর্ণনা করে যা দেখতে দেখতে ( idপ্রতিটি আইটেমকে উপস্থাপন করে):

 1
 + - 2
 | + - 3
 | + - 4
 |
 + - 5
     + - 6
     + - 7

বা, নেস্টেড সেট ডায়াগ্রাম হিসাবে যা এটি আরও স্পষ্ট করে তোলে যে কীভাবে lftএবং rghtমানগুলি কাজ করে:

 __________________________________________________________________________
| রুট 1 |
| ________________________________ ________________________________ |
| | শিশু 1.1 | | শিশু ১.২ | |
| | ___________ ___________ | | ___________ ___________ | |
| | | সি 1.1.1 | | সি 1.1.2 | | | | সি 1.2.1 | | সি 1.2.2 | | |
1 2 3___________4 5___________6 7 8 9___________10 11__________12 13 14
| | ________________________________ | | ________________________________ | |
| __________________________________________________________________________ |

যেমন আপনি দেখতে পাচ্ছেন, গাছের ক্রমে কোনও নির্দিষ্ট নোডের জন্য পুরো সাবট্রিটি পেতে, আপনাকে কেবল সমস্ত সারি নির্বাচন করতে হবে যা এর lftএবং rghtমানগুলির মধ্যে রয়েছে lftএবং এর rghtমানগুলি রয়েছে। প্রদত্ত নোডের জন্য পূর্বপুরুষদের গাছটি পুনরুদ্ধার করাও সহজ।

levelকলাম সবকিছু বাদ দিয়েও সুবিধার জন্য denormalisation একটি বিট এবং tree_idকলাম আপনি পুনরায় আরম্ভ করতে পারবেন lftএবং rghtযেমন, প্রতিটি টপ লেভেল নোড, যা টিপে, প্যাচসমূহ এবং মুছে দেওয়া দ্বারা প্রভাবিত কলামের সংখ্যা হ্রাস জন্য সংখ্যায়ন lftএবং rghtকলাম হতে হবে এই অপারেশনগুলি ফাঁক তৈরি করতে বা বন্ধ করার জন্য সঞ্চালিত হলে সেই অনুযায়ী সামঞ্জস্য করা। আমি প্রতিটি অপারেশনের জন্য প্রয়োজনীয় প্রশ্নের চারপাশে আমার মাথা গুটিয়ে দেওয়ার চেষ্টা করছিলাম তখন আমি কিছু বিকাশ নোট তৈরি করেছি ।

গাছটি প্রদর্শনের জন্য এই ডেটার সাথে প্রকৃতপক্ষে কাজ করার শর্তে, আমি একটি tree_item_iteratorইউটিলিটি ফাংশন তৈরি করেছি যা প্রতিটি নোডের জন্য, আপনার পছন্দসই প্রদর্শনটি উত্পন্ন করার জন্য আপনাকে পর্যাপ্ত তথ্য দিতে হবে।

এমপিটিটি সম্পর্কে আরও তথ্য:


9
আমি আশা করি আমরা কলাম নামের মতো lftএবং সংক্ষিপ্তসারগুলি ব্যবহার বন্ধ rghtকরব, আমার অর্থ আমরা কতগুলি অক্ষর টাইপ করতে পারি নি? এক?!
orustammanapov

21

এটি বেশ পুরানো প্রশ্ন, তবে এটির অনেকগুলি মতামত পেয়েছি বলে আমি মনে করি এটি একটি বিকল্প উপস্থাপনের পক্ষে মূল্যবান এবং আমার মতে খুব মার্জিত, সমাধান।

গাছের কাঠামো পড়তে আপনি পুনরাবৃত্ত সাধারণ টেবিল এক্সপ্রেশন (সিটিই) ব্যবহার করতে পারেন । এটি একবারে পুরো গাছের কাঠামো আনার সম্ভাবনা দেয়, নোডের স্তর সম্পর্কে তার পিতামাতার নোড এবং পিতামাতার নোডের বাচ্চাদের মধ্যে অর্ডার সম্পর্কে তথ্য থাকতে পারে।

আমাকে পোস্টগ্র্রেএসকিউএল 9.1 এ কীভাবে কাজ করবে তা আপনাকে দেখাতে দিন।

  1. একটি কাঠামো তৈরি করুন

    CREATE TABLE tree (
        id int  NOT NULL,
        name varchar(32)  NOT NULL,
        parent_id int  NULL,
        node_order int  NOT NULL,
        CONSTRAINT tree_pk PRIMARY KEY (id),
        CONSTRAINT tree_tree_fk FOREIGN KEY (parent_id) 
          REFERENCES tree (id) NOT DEFERRABLE
    );
    
    
    insert into tree values
      (0, 'ROOT', NULL, 0),
      (1, 'Node 1', 0, 10),
      (2, 'Node 1.1', 1, 10),
      (3, 'Node 2', 0, 20),
      (4, 'Node 1.1.1', 2, 10),
      (5, 'Node 2.1', 3, 10),
      (6, 'Node 1.2', 1, 20);
  2. একটি কোয়েরি লিখুন

    WITH RECURSIVE 
    tree_search (id, name, level, parent_id, node_order) AS (
      SELECT 
        id, 
        name,
        0,
        parent_id, 
        1 
      FROM tree
      WHERE parent_id is NULL
    
      UNION ALL 
      SELECT 
        t.id, 
        t.name,
        ts.level + 1, 
        ts.id, 
        t.node_order 
      FROM tree t, tree_search ts 
      WHERE t.parent_id = ts.id 
    ) 
    SELECT * FROM tree_search 
    WHERE level > 0 
    ORDER BY level, parent_id, node_order;

    ফলাফল এখানে:

     id |    name    | level | parent_id | node_order 
    ----+------------+-------+-----------+------------
      1 | Node 1     |     1 |         0 |         10
      3 | Node 2     |     1 |         0 |         20
      2 | Node 1.1   |     2 |         1 |         10
      6 | Node 1.2   |     2 |         1 |         20
      5 | Node 2.1   |     2 |         3 |         10
      4 | Node 1.1.1 |     3 |         2 |         10
    (6 rows)

    গাছের নোডগুলি গভীরতার একটি স্তর দ্বারা অর্ডার করা হয়। চূড়ান্ত আউটপুটে আমরা তাদের পরবর্তী লাইনে উপস্থাপন করব।

    প্রতিটি স্তরের জন্য, তাদের প্যারেন্ট_আইড এবং পিতামাতার মধ্যে নোড_র্ডার দ্বারা অর্ডার করা হয়। এটি আমাদের আউটপুটে কীভাবে উপস্থাপন করতে পারে - এই ক্রমে পিতামাতার সাথে লিঙ্ক নোড।

    এই জাতীয় কাঠামো থাকলে এইচটিএমএলটিতে সত্যিই দুর্দান্ত উপস্থাপনা করা কঠিন হবে না।

    রিকার্সিভ সিটিই পোস্টগ্র্রেএসকিউএল, আইবিএম ডিবি 2, এমএস এসকিউএল সার্ভার এবং ওরাকল এ উপলব্ধ

    আপনি যদি পুনরাবৃত্ত এসকিউএল ক্যোয়ারীগুলিতে আরও পড়তে চান তবে আপনি হয় আপনার প্রিয় ডিবিএমএসের ডকুমেন্টেশন চেক করতে পারেন বা এই বিষয়টি সহ আমার দুটি নিবন্ধ পড়তে পারেন:


18

ওরাকল 9 আই হিসাবে, আপনি সংযোগ ব্যবহার করতে পারেন can

SELECT LPAD(' ', (LEVEL - 1) * 4) || "Name" AS "Name"
FROM (SELECT * FROM TMP_NODE ORDER BY "Order")
CONNECT BY PRIOR "Id" = "ParentId"
START WITH "Id" IN (SELECT "Id" FROM TMP_NODE WHERE "ParentId" = 0)

এসকিউএল সার্ভার 2005 হিসাবে, আপনি একটি পুনরাবৃত্ত সাধারণ টেবিল এক্সপ্রেশন (সিটিই) ব্যবহার করতে পারেন।

WITH [NodeList] (
  [Id]
  , [ParentId]
  , [Level]
  , [Order]
) AS (
  SELECT [Node].[Id]
    , [Node].[ParentId]
    , 0 AS [Level]
    , CONVERT([varchar](MAX), [Node].[Order]) AS [Order]
  FROM [Node]
  WHERE [Node].[ParentId] = 0
  UNION ALL
  SELECT [Node].[Id]
    , [Node].[ParentId]
    , [NodeList].[Level] + 1 AS [Level]
    , [NodeList].[Order] + '|'
      + CONVERT([varchar](MAX), [Node].[Order]) AS [Order]
  FROM [Node]
    INNER JOIN [NodeList] ON [NodeList].[Id] = [Node].[ParentId]
) SELECT REPLICATE(' ', [NodeList].[Level] * 4) + [Node].[Name] AS [Name]
FROM [Node]
  INNER JOIN [NodeList] ON [NodeList].[Id] = [Node].[Id]
ORDER BY [NodeList].[Order]

উভয়ই নিম্নলিখিত ফলাফলগুলি আউটপুট দেবে।

নাম
'নোড 1'
'নোড ১.১'
'নোড 1.1.1'
'নোড ১.২'
'নোড 2'
'নোড ২.১'

সিটি স্কেলসার্ভার এবং ওরাকল উভয়ই @ এরিক ওয়েলনাউ
নিসার

9

বিলের উত্তরটি বেশ গোশত-দারুণ ভাল, এই উত্তরটি এতে কিছু জিনিস যুক্ত করেছে যা আমাকে এস ও থ্রেডেড উত্তরগুলি সমর্থন করার ইচ্ছুক করে তোলে।

যাইহোক আমি গাছের কাঠামো এবং অর্ডার সম্পত্তি সমর্থন করতে চেয়েছিলাম। আমি প্রতিটি নোডে বলা একক সম্পত্তি অন্তর্ভুক্ত করেছি যা মূল প্রশ্নে leftSiblingএকই জিনিস Orderকরা বোঝায় (বাম থেকে ডান ক্রম বজায় রাখুন)।

mysql> ডেস্ক নোড;
+ + ------------- + + -------------- + + ------ + + ----- + + ------- - + + ---------------- + +
| মাঠ | প্রকার | নাল | কী | ডিফল্ট | অতিরিক্ত |
+ + ------------- + + -------------- + + ------ + + ----- + + ------- - + + ---------------- + +
| আইডি | int (11) | না | পিআরআই | নুল | স্বতঃআগ্রহ |
| নাম | varchar (255) | হ্যাঁ | | নুল | |
| বামসিলিং | int (11) | না | | 0 | |
+ + ------------- + + -------------- + + ------ + + ----- + + ------- - + + ---------------- + +
3 টি সারি সেট (0.00 সেকেন্ড)

mysql> desc সংলগ্ন;
+ + ------------ + + --------- + + ------ + + ----- + + --------- + + --- ------------- + +
| মাঠ | প্রকার | নাল | কী | ডিফল্ট | অতিরিক্ত |
+ + ------------ + + --------- + + ------ + + ----- + + --------- + + --- ------------- + +
| রিলেশনআইডি | int (11) | না | পিআরআই | নুল | স্বতঃআগ্রহ |
| অভিভাবক | int (11) | না | | নুল | |
| শিশু | int (11) | না | | নুল | |
| পাথলেন | int (11) | না | | নুল | |
+ + ------------ + + --------- + + ------ + + ----- + + --------- + + --- ------------- + +
4 টি সারি সেট (0.00 সেকেন্ড)

আমার ব্লগে আরও বিশদ এবং এসকিউএল কোড

ধন্যবাদ বিল আপনার উত্তর শুরু করতে সহায়ক ছিল!


7

ভাল পছন্দ দেওয়া হয়েছে, আমি অবজেক্ট ব্যবহার করব। আমি প্রতিটি রেকর্ডের জন্য একটি অবজেক্ট তৈরি করতাম যেখানে প্রতিটি বস্তুর childrenসংগ্রহ থাকে এবং সেগুলি সমস্ত একটি এসোয়্যার অ্যারে (/ হ্যাশটেবল) যেখানে আইডিটি মূল সেখানে সংরক্ষণ করে। এবং সংগ্রহের মাধ্যমে একবারে ব্লিটজগুলি, প্রাসঙ্গিক শিশুদের ক্ষেত্রগুলিতে বাচ্চাদের যুক্ত করে। সহজ।

তবে কিছু ভাল ওওপি ব্যবহার সীমাবদ্ধ করে আপনি মজা করছেন না বলে আমি সম্ভবত এর উপর ভিত্তি করে পুনরাবৃত্তি করব:

function PrintLine(int pID, int level)
    foreach record where ParentID == pID
        print level*tabs + record-data
        PrintLine(record.ID, level + 1)

PrintLine(0, 0)

সম্পাদনা: এটি অন্যান্য কয়েকটি এন্ট্রিগুলির মতো, তবে আমি মনে করি এটি কিছুটা পরিষ্কার। একটি জিনিস আমি যুক্ত করব: এটি অত্যন্ত এসকিউএল-নিবিড়। এটা খারাপআপনার যদি পছন্দ হয় তবে ওওপি রুটে যান।


এটাই আমি "ফ্রেমওয়ার্ক না" বলতে চাইছিলাম - আপনি লিনকিউ ব্যবহার করছেন, তাই না? আপনার প্রথম অনুচ্ছেদ সম্পর্কে: ফলাফল সেট ইতিমধ্যে রয়েছে, কেন সমস্ত তথ্য প্রথমে একটি নতুন অবজেক্ট স্ট্রাকচারে অনুলিপি করা হচ্ছে? (আমি এ বিষয়ে যথেষ্ট পরিষ্কার ছিলাম না, দুঃখিত)
টমলক

তোমালাক - কোনও কোড সিউডো-কোড নয়। অবশ্যই আপনাকে জিনিসগুলি যথাযথ বাছাই এবং পুনরাবৃত্তকারীগুলিতে ছড়িয়ে দিতে হবে ... এবং একটি বাস্তব বাক্য গঠন! ওওপ কেন? কারণ আপনি ঠিক কাঠামো আয়না করতে পারেন। এটি জিনিসগুলি সুন্দর রাখে এবং এটি কেবল আরও দক্ষ হওয়ার জন্য ঘটে (কেবলমাত্র একটি নির্বাচন করুন)
ওলি

আমার মনেও কোনও পুনরাবৃত্তি নির্বাচন ছিল না। ওওপি সম্পর্কিত: মার্ক বেসি তার উত্তরে বলেছিলেন: "আপনি হ্যাশম্যাপের সাহায্যে অন্য কোনও ডেটা স্ট্রাকচার অনুকরণ করতে পারেন, এটি কোনও ভয়ানক সীমাবদ্ধতা নয়"। আপনার সমাধানটি সঠিক, তবে আমি মনে করি ওওপি ছাড়াই কিছু ঘরের সামনের উন্নতি রয়েছে।
তোমালাক

5

এটি দ্রুত লেখা হয়েছিল, এবং এটি চমত্কার বা দক্ষও নয় (প্লাস এটি অটোবক্সগুলি মধ্যে রূপান্তরিত করে intএবং Integerবিরক্তিকর!), তবে এটি কার্যকর হয়।

এটি সম্ভবত নিয়মগুলি ভঙ্গ করেছে যেহেতু আমি আমার নিজস্ব অবজেক্ট তৈরি করছি তবে আরে আমি বাস্তব কাজ থেকে ডাইভার্সন হিসাবে এটি করছি :)

এটিও ধরে নিয়েছে যে নোডগুলি তৈরি করা শুরু করার আগে রেজাল্টসেট / টেবিলটি পুরো কোনও কাঠামোর মধ্যে পুরোপুরি পড়তে হবে, এটি যদি আপনার কয়েক হাজার সারি থাকে তবে সেরা সমাধান হতে পারে না।

public class Node {

    private Node parent = null;

    private List<Node> children;

    private String name;

    private int id = -1;

    public Node(Node parent, int id, String name) {
        this.parent = parent;
        this.children = new ArrayList<Node>();
        this.name = name;
        this.id = id;
    }

    public int getId() {
        return this.id;
    }

    public String getName() {
        return this.name;
    }

    public void addChild(Node child) {
        children.add(child);
    }

    public List<Node> getChildren() {
        return children;
    }

    public boolean isRoot() {
        return (this.parent == null);
    }

    @Override
    public String toString() {
        return "id=" + id + ", name=" + name + ", parent=" + parent;
    }
}

public class NodeBuilder {

    public static Node build(List<Map<String, String>> input) {

        // maps id of a node to it's Node object
        Map<Integer, Node> nodeMap = new HashMap<Integer, Node>();

        // maps id of a node to the id of it's parent
        Map<Integer, Integer> childParentMap = new HashMap<Integer, Integer>();

        // create special 'root' Node with id=0
        Node root = new Node(null, 0, "root");
        nodeMap.put(root.getId(), root);

        // iterate thru the input
        for (Map<String, String> map : input) {

            // expect each Map to have keys for "id", "name", "parent" ... a
            // real implementation would read from a SQL object or resultset
            int id = Integer.parseInt(map.get("id"));
            String name = map.get("name");
            int parent = Integer.parseInt(map.get("parent"));

            Node node = new Node(null, id, name);
            nodeMap.put(id, node);

            childParentMap.put(id, parent);
        }

        // now that each Node is created, setup the child-parent relationships
        for (Map.Entry<Integer, Integer> entry : childParentMap.entrySet()) {
            int nodeId = entry.getKey();
            int parentId = entry.getValue();

            Node child = nodeMap.get(nodeId);
            Node parent = nodeMap.get(parentId);
            parent.addChild(child);
        }

        return root;
    }
}

public class NodePrinter {

    static void printRootNode(Node root) {
        printNodes(root, 0);
    }

    static void printNodes(Node node, int indentLevel) {

        printNode(node, indentLevel);
        // recurse
        for (Node child : node.getChildren()) {
            printNodes(child, indentLevel + 1);
        }
    }

    static void printNode(Node node, int indentLevel) {
        StringBuilder sb = new StringBuilder();
        for (int i = 0; i < indentLevel; i++) {
            sb.append("\t");
        }
        sb.append(node);

        System.out.println(sb.toString());
    }

    public static void main(String[] args) {

        // setup dummy data
        List<Map<String, String>> resultSet = new ArrayList<Map<String, String>>();
        resultSet.add(newMap("1", "Node 1", "0"));
        resultSet.add(newMap("2", "Node 1.1", "1"));
        resultSet.add(newMap("3", "Node 2", "0"));
        resultSet.add(newMap("4", "Node 1.1.1", "2"));
        resultSet.add(newMap("5", "Node 2.1", "3"));
        resultSet.add(newMap("6", "Node 1.2", "1"));

        Node root = NodeBuilder.build(resultSet);
        printRootNode(root);

    }

    //convenience method for creating our dummy data
    private static Map<String, String> newMap(String id, String name, String parentId) {
        Map<String, String> row = new HashMap<String, String>();
        row.put("id", id);
        row.put("name", name);
        row.put("parent", parentId);
        return row;
    }
}

প্রচুর উত্স কোডের সাথে উপস্থাপিত হওয়ার সময় প্রয়োগকরণ-নির্দিষ্ট অংশ থেকে অ্যালগরিদম-নির্দিষ্ট অংশটি ফিল্টার করা আমার সবসময় কঠিন মনে হয়। সে কারণেই আমি এমন একটি সমাধান চেয়েছিলাম যা প্রথমে ভাষা-নির্দিষ্ট নয়। তবে এটি কাজ করে, তাই আপনার সময়ের জন্য ধন্যবাদ!
তোমালাক

আমি এখন আপনাকে কী বোঝাতে চাইছি, যদি এটি স্পষ্ট না হয় তবে প্রধান অ্যালগরিদমটি নোডবিল্ডার.বিল্ড () এ রয়েছে - আমি সম্ভবত এটির সংক্ষেপণের আরও ভাল কাজ করতে পারতাম।
ম্যাট বি

5

সত্যই ভাল সমাধান রয়েছে যা বর্গক্ষেত্র সূচকগুলির অভ্যন্তরীণ btree প্রতিনিধিত্বকে কাজে লাগায়। এটি 1998 সালের দিকে কিছু দুর্দান্ত গবেষণার ভিত্তিতে তৈরি।

এখানে একটি উদাহরণ সারণী (মাইএসকিএল)।

CREATE TABLE `node` (
  `id` int(10) unsigned NOT NULL AUTO_INCREMENT,
  `name` varchar(255) NOT NULL,
  `tw` int(10) unsigned NOT NULL,
  `pa` int(10) unsigned DEFAULT NULL,
  `sz` int(10) unsigned DEFAULT NULL,
  `nc` int(11) GENERATED ALWAYS AS (tw+sz) STORED,
  PRIMARY KEY (`id`),
  KEY `node_tw_index` (`tw`),
  KEY `node_pa_index` (`pa`),
  KEY `node_nc_index` (`nc`),
  CONSTRAINT `node_pa_fk` FOREIGN KEY (`pa`) REFERENCES `node` (`tw`) ON DELETE CASCADE
)

গাছের প্রতিনিধিত্বের জন্য প্রয়োজনীয় ক্ষেত্রগুলি হ'ল:

  • tw: বাম থেকে ডান ডিএফএস প্রি-অর্ডার সূচক, যেখানে রুট = 1।
  • পা: প্যারেন্ট নোডের রেফারেন্স (টু ব্যবহার করে), শিকড়টি শূন্য।
  • sz: নোডের শাখার আকার নিজেই।
  • এনসি: সিনট্যাকটিক চিনি হিসাবে ব্যবহৃত হয়। এটি দ্বিগুণ + এনসি এবং নোডের "পরবর্তী শিশু" এর দুটি উপস্থাপন করে।

এখানে 24 টি নোডের একটি উদাহরণ যা দ্বিগুণ দ্বারা অর্ডার করা হয়েছে:

+-----+---------+----+------+------+------+
| id  | name    | tw | pa   | sz   | nc   |
+-----+---------+----+------+------+------+
|   1 | Root    |  1 | NULL |   24 |   25 |
|   2 | A       |  2 |    1 |   14 |   16 |
|   3 | AA      |  3 |    2 |    1 |    4 |
|   4 | AB      |  4 |    2 |    7 |   11 |
|   5 | ABA     |  5 |    4 |    1 |    6 |
|   6 | ABB     |  6 |    4 |    3 |    9 |
|   7 | ABBA    |  7 |    6 |    1 |    8 |
|   8 | ABBB    |  8 |    6 |    1 |    9 |
|   9 | ABC     |  9 |    4 |    2 |   11 |
|  10 | ABCD    | 10 |    9 |    1 |   11 |
|  11 | AC      | 11 |    2 |    4 |   15 |
|  12 | ACA     | 12 |   11 |    2 |   14 |
|  13 | ACAA    | 13 |   12 |    1 |   14 |
|  14 | ACB     | 14 |   11 |    1 |   15 |
|  15 | AD      | 15 |    2 |    1 |   16 |
|  16 | B       | 16 |    1 |    1 |   17 |
|  17 | C       | 17 |    1 |    6 |   23 |
| 359 | C0      | 18 |   17 |    5 |   23 |
| 360 | C1      | 19 |   18 |    4 |   23 |
| 361 | C2(res) | 20 |   19 |    3 |   23 |
| 362 | C3      | 21 |   20 |    2 |   23 |
| 363 | C4      | 22 |   21 |    1 |   23 |
|  18 | D       | 23 |    1 |    1 |   24 |
|  19 | E       | 24 |    1 |    1 |   25 |
+-----+---------+----+------+------+------+

প্রতিটি গাছের ফলাফল পুনরাবৃত্তির সাথে করা যায়। উদাহরণস্বরূপ, নোডের পূর্বসূরিদের তালিকা পেতে tw = '22 'এ

পূর্বপুরুষ

select anc.* from node me,node anc 
where me.tw=22 and anc.nc >= me.tw and anc.tw <= me.tw 
order by anc.tw;
+-----+---------+----+------+------+------+
| id  | name    | tw | pa   | sz   | nc   |
+-----+---------+----+------+------+------+
|   1 | Root    |  1 | NULL |   24 |   25 |
|  17 | C       | 17 |    1 |    6 |   23 |
| 359 | C0      | 18 |   17 |    5 |   23 |
| 360 | C1      | 19 |   18 |    4 |   23 |
| 361 | C2(res) | 20 |   19 |    3 |   23 |
| 362 | C3      | 21 |   20 |    2 |   23 |
| 363 | C4      | 22 |   21 |    1 |   23 |
+-----+---------+----+------+------+------+

ভাইবোন এবং বাচ্চারা তুচ্ছ - কেবল মাত্র দুটি দ্বারা পিএ ফিল্ড অর্ডার ব্যবহার করুন।

উত্তরপুরূষ

উদাহরণস্বরূপ নোডগুলির সেট (শাখা) যা tw = 17 এ মূলযুক্ত।

select des.* from node me,node des 
where me.tw=17 and des.tw < me.nc and des.tw >= me.tw 
order by des.tw;
+-----+---------+----+------+------+------+
| id  | name    | tw | pa   | sz   | nc   |
+-----+---------+----+------+------+------+
|  17 | C       | 17 |    1 |    6 |   23 |
| 359 | C0      | 18 |   17 |    5 |   23 |
| 360 | C1      | 19 |   18 |    4 |   23 |
| 361 | C2(res) | 20 |   19 |    3 |   23 |
| 362 | C3      | 21 |   20 |    2 |   23 |
| 363 | C4      | 22 |   21 |    1 |   23 |
+-----+---------+----+------+------+------+

অতিরিক্ত নোট

সন্নিবেশ বা আপডেটের চেয়ে অনেক বেশি সংখ্যক পাঠের ক্ষেত্রে এই পদ্ধতিটি অত্যন্ত কার্যকর extremely

যেহেতু গাছের নোড সন্নিবেশ, চলন বা আপডেট করার জন্য গাছটি সামঞ্জস্য করা প্রয়োজন, ক্রিয়াটি শুরু করার আগে টেবিলটি লক করা প্রয়োজন necessary

সন্নিবেশ / মুছে ফেলার ব্যয় বেশি কারণ দ্বি সূচক এবং sz (শাখার আকার) মানগুলি সন্নিবেশ বিন্দুর পরে সমস্ত নোডে এবং যথাক্রমে সমস্ত পূর্বপুরুষের জন্য আপডেট করতে হবে।

শাখা চলাচলে শাখার দ্বিগুণ মান সীমাবদ্ধতার বাইরে চলে যাওয়া জড়িত, সুতরাং একটি শাখা সরানোর সময় বিদেশী কী সীমাবদ্ধতাগুলি অক্ষম করাও প্রয়োজনীয়। একটি শাখা সরানোর জন্য মূলত চারটি প্রশ্নের প্রয়োজন:

  • ব্রাঞ্চটি সীমার বাইরে নিয়ে যান।
  • যে ফাঁক ফেলেছিল তা বন্ধ করুন। (বাকি গাছটি এখন স্বাভাবিক করা হয়েছে)।
  • ফাঁকটি যেখানে যাবে সেখানে খুলুন।
  • শাখাটিকে নতুন অবস্থানে নিয়ে যান।

গাছের প্রশ্নগুলি সামঞ্জস্য করুন

গাছের ফাঁক ফাঁক করা / বন্ধ করা একটি গুরুত্বপূর্ণ উপ-ফাংশন যা তৈরি / আপডেট / মুছতে পদ্ধতিগুলি ব্যবহার করে, তাই আমি এটি এখানে অন্তর্ভুক্ত করি।

আমাদের দুটি প্যারামিটার প্রয়োজন - একটি পতাকা আমাদের প্রতিনিধিত্ব করে বা আপসাইজ করা হয় কিনা এবং নোডের বার সূচকটি উপস্থাপন করে। সুতরাং, উদাহরণস্বরূপ tw = 18 (যার একটি শাখার আকার 5)। আসুন ধরে নেওয়া যাক আমরা ডাউনসাইজিং করছি (দুটি মুছে ফেলছি) - এর অর্থ হ'ল আমরা নীচের উদাহরণের আপডেটগুলিতে '+' এর পরিবর্তে '-' ব্যবহার করছি।

Sz মান আপডেট করার জন্য আমরা প্রথমে একটি (কিছুটা পরিবর্তিত) পূর্বপুরুষের ফাংশন ব্যবহার করি।

update node me, node anc set anc.sz = anc.sz - me.sz from 
node me, node anc where me.tw=18 
and ((anc.nc >= me.tw and anc.tw < me.pa) or (anc.tw=me.pa));

তারপরে আমাদের ডাবগুলি মুছে ফেলার জন্য যাদের ডাবল শাখা তুলনায় বেশি for

update node me, node anc set anc.tw = anc.tw - me.sz from 
node me, node anc where me.tw=18 and anc.tw >= me.tw;

তারপরে আমাদের পিতামাতার সামঞ্জস্য করা উচিত যাদের পায়ের বারটি শাখাটি সরানোর চেয়ে বেশি।

update node me, node anc set anc.pa = anc.pa - me.sz from 
node me, node anc where me.tw=18 and anc.pa >= me.tw;

3

ধরে নিই যে আপনি জানেন যে মূল উপাদানগুলি শূন্য, এখানে পাঠ্যকে আউটপুট দেওয়ার সিউডোকোড:

function PrintLevel (int curr, int level)
    //print the indents
    for (i=1; i<=level; i++)
        print a tab
    print curr \n;
    for each child in the table with a parent of curr
        PrintLevel (child, level+1)


for each elementID where the parentid is zero
    PrintLevel(elementID, 0)

3

আপনি হ্যাশম্যাপের সাহায্যে অন্য কোনও ডেটা স্ট্রাকচার অনুকরণ করতে পারেন, এটি কোনও ভয়ানক সীমাবদ্ধতা নয়। উপরে থেকে নীচে পর্যন্ত স্ক্যান করে, আপনি প্রতিটি কলামের জন্য একটি এন্ট্রি সহ ডাটাবেসের প্রতিটি সারিটির জন্য একটি হ্যাশম্যাপ তৈরি করেন। এই আইডিটিতে কীড করে একটি "মাস্টার" হ্যাশম্যাপে এই প্রতিটি হ্যাশম্যাপ যুক্ত করুন। যদি কোনও নোডের এমন "প্যারেন্ট" থাকে যা আপনি এখনও দেখেন নি তবে মাস্টার হ্যাশম্যাপে এর জন্য একটি স্থানধারক এন্ট্রি তৈরি করুন এবং আপনি আসল নোডটি দেখলে তা পূরণ করুন।

এটিকে মুদ্রণ করতে, পথে ইনডেন্ট স্তরের ট্র্যাক রেখে ডেটা দিয়ে একটি সাধারণ গভীরতা-প্রথম পাস করুন। আপনি প্রতিটি সারিটির জন্য "শিশুদের" এন্ট্রি রেখে এবং ডেটা স্ক্যান করার সাথে সাথে এটিকে জনপ্রিয় করে এটিকে আরও সহজ করে তুলতে পারেন।

কোনও ডাটাবেসে একটি গাছ সংরক্ষণ করার "আরও ভাল" উপায় আছে কিনা তা নির্ভর করে আপনি কীভাবে ডেটা ব্যবহার করতে চলেছেন তার উপর নির্ভর করে। আমি এমন সিস্টেমগুলি দেখেছি যার জ্ঞাত সর্বাধিক গভীরতা ছিল যা স্তরক্রমের প্রতিটি স্তরের জন্য আলাদা টেবিল ব্যবহার করে। গাছের স্তরগুলি সর্বোপরি সমান না হলে (শীর্ষ স্তরের বিভাগগুলি পাতার চেয়ে পৃথক হয়ে থাকে) এটি অনেক অর্থবোধ করে।


1

যদি নেস্টেড হ্যাশ ম্যাপ বা অ্যারে তৈরি করা যায় তবে আমি প্রথম থেকেই টেবিলের নীচে যেতে পারি এবং প্রতিটি আইটেমকে নেস্টেড অ্যারেতে যুক্ত করতে পারি। নেস্টেড অ্যারেতে কোন স্তরটি সন্নিবেশ করানো হবে তা জানতে আমার অবশ্যই প্রতিটি লাইনটি রুট নোডে সন্ধান করতে হবে। আমি স্মৃতিশক্তি নিয়োগ করতে পারি যাতে আমাকে বার বার একই পিতামাতাকে দেখার প্রয়োজন হয় না।

সম্পাদনা: আমি পুরো টেবিলটি প্রথমে একটি অ্যারেতে পড়ব, সুতরাং এটি ডিবিটিকে বারবার জিজ্ঞাসা করবে না। আপনার টেবিলটি খুব বড় হলে অবশ্যই এটি ব্যবহারিক হবে না।

কাঠামোটি তৈরি হওয়ার পরে, আমাকে অবশ্যই এটির মধ্য দিয়ে গভীরতার প্রথমটি করতে হবে এবং এইচটিএমএল প্রিন্ট আউট করতে হবে।

একটি তথ্য সারণী ব্যবহার করে এই তথ্য সংরক্ষণের আর কোনও ভাল মৌলিক উপায় নেই (যদিও আমি ভুল হতে পারি;), এবং আরও ভাল সমাধান দেখতে পছন্দ করব) তবে, আপনি যদি গতিশীলভাবে তৈরি ডিবি টেবিলগুলিকে নিয়োগ করার জন্য একটি স্কিম তৈরি করেন, তবে আপনি সরলতার ত্যাগ এবং এসকিউএল হেলকের ঝুঁকিতে একটি সম্পূর্ণ নতুন বিশ্ব উন্মুক্ত করেছেন;)।


1
আমি বরং ডিবি লেআউটটি পরিবর্তন করব না কারণ কেবলমাত্র একটি নতুন স্তরের সাব-নোডের প্রয়োজন। :-)
টমলক

1

যদি উপাদানগুলি গাছের ক্রমে থাকে, যেমন আপনার উদাহরণে দেখানো হয়েছে, আপনি নীচের পাইথনের উদাহরণের মতো কিছু ব্যবহার করতে পারেন:

delimiter = '.'
stack = []
for item in items:
  while stack and not item.startswith(stack[-1]+delimiter):
    print "</div>"
    stack.pop()
  print "<div>"
  print item
  stack.append(item)

এটি যা করে তা গাছের বর্তমান অবস্থানের প্রতিনিধিত্ব করে একটি স্ট্যাক বজায় রাখা। সারণীর প্রতিটি উপাদানের জন্য, এটি বর্তমান আইটেমটির পিতামাতাকে না পাওয়া পর্যন্ত এটি স্ট্যাক উপাদানগুলিকে (ম্যাচিং ডিভগুলি বন্ধ করে) পপ করে। তারপরে এটি সেই নোডের শুরুটিকে আউটপুট করে এবং স্ট্যাকের দিকে ঠেলে দেয়।

যদি আপনি নেস্টেড উপাদানগুলির পরিবর্তে ইনডেন্টিং ব্যবহার করে গাছটিকে আউটপুট করতে চান তবে ডিভগুলি মুদ্রণ করতে আপনি মুদ্রণ বিবৃতিগুলি এড়িয়ে যেতে পারেন এবং প্রতিটি আইটেমের আগে স্ট্যাকের আকারের একাধিক সংখ্যক সমান স্থান মুদ্রণ করতে পারেন। উদাহরণস্বরূপ, পাইথনে:

print "  " * len(stack)

নেস্টেড তালিকা বা অভিধানের একটি সেট তৈরি করতে আপনি সহজেই এই পদ্ধতিটি ব্যবহার করতে পারেন।

সম্পাদনা: আমি আপনার স্পষ্টতা থেকে দেখছি যে নামগুলি নোড পাথের উদ্দেশ্যে নয়। এটি বিকল্প পদ্ধতির পরামর্শ দেয়:

idx = {}
idx[0] = []
for node in results:
  child_list = []
  idx[node.Id] = child_list
  idx[node.ParentId].append((node, child_list))

এটি টিপলস (!) এর অ্যারেগুলির একটি গাছ তৈরি করে। idx [0] গাছের মূল (গুলি) উপস্থাপন করে। অ্যারের প্রতিটি উপাদান হ'ল নোড এবং এর সমস্ত শিশুদের একটি তালিকা সমন্বিত একটি 2-টুপল। একবার নির্মিত হয়ে গেলে আপনি আইডিএক্স ধরে রাখতে পারেন [0] এবং আইডিএক্স বাতিল করতে পারেন, যদি না আপনি তাদের আইডি দ্বারা নোডগুলি অ্যাক্সেস করতে চান।


1

বিলের এসকিউএল সমাধান বাড়ানোর জন্য আপনি মূলত ফ্ল্যাট অ্যারে ব্যবহার করে একই কাজ করতে পারেন। আরও যদি আপনার স্ট্রিংগুলির একই দৈর্ঘ্য হয় এবং আপনার সর্বাধিক সংখ্যক শিশু পরিচিত হয় (একটি বাইনারি গাছে বলুন) আপনি এটি একটি একক স্ট্রিং (অক্ষর অ্যারে) ব্যবহার করে করতে পারেন। আপনার যদি নির্বিচারে বাচ্চাদের সংখ্যা থাকে এটি কিছুটা জটিল করে তোলে ... আমাকে কী করা যায় তা দেখতে আমার পুরানো নোটগুলি পরীক্ষা করতে হবে।

তারপরে, কিছুটা মেমোরির কোরবানি, বিশেষত আপনার গাছটি যদি দুর্যোগপূর্ণ এবং / বা অবিকৃত না হয়, আপনি কিছুটা সূচক গণিত দিয়ে, আপনার গাছটিকে যথাযথভাবে অ্যারেতে প্রথম প্রস্থ সংরক্ষণ করে এলোমেলোভাবে সমস্ত স্ট্রিং অ্যাক্সেস করতে পারেন (বাইনারি হিসাবে গাছ):

String[] nodeArray = [L0root, L1child1, L1child2, L2Child1, L2Child2, L2Child3, L2Child4] ...

আপনি আপনার স্ট্রিংয়ের দৈর্ঘ্য জানেন, আপনি এটি জানেন

আমি এখন কর্মে আছি তাই এতে বেশি সময় ব্যয় করতে পারি না তবে আগ্রহের সাথে আমি এটি করার জন্য কিছুটা কোড আনতে পারি।

আমরা এটি ডিএনএ কোডন দিয়ে তৈরি বাইনারি গাছগুলিতে অনুসন্ধান করতে ব্যবহার করি, একটি প্রক্রিয়া গাছটি তৈরি করেছিল, তারপরে আমরা পাঠ্য নিদর্শনগুলি অনুসন্ধান করার জন্য এটি সমতল করেছিলাম এবং যখন পাওয়া যায়, তবে সূচি গণিত (উপরে থেকে উল্টো) আমরা নোডটি ফিরে পাই ... খুব দ্রুত এবং দক্ষ, শক্ত আমাদের গাছে খুব কমই খালি নোড ছিল, তবে আমরা এক মুহুর্তে গিগাবাইটের ডেটা সিয়ার করতে পারি।


0

হায়ারার্কিয়াল স্ট্রাকচারের জন্য নিও 4 জ এর মতো নোসকিএল সরঞ্জামগুলি ব্যবহার করার বিষয়ে ভাবুন। উদাহরণস্বরূপ একটি নেটওয়ার্ক অ্যাপ্লিকেশন যেমন লিংকডিন কাউচবাস ব্যবহার করে (অন্য একটি এনএসকিএল সমাধান)

তবে কেবল ডেটা-মার্ট স্তরের প্রশ্নের জন্য এবং লেনদেন সংরক্ষণ / রক্ষণাবেক্ষণের জন্য নোসকিএল ব্যবহার করুন


এসকিউএল এবং "নন-টেবিল" কাঠামোর জটিলতা এবং পারফেক্টটি পড়ার পরে, এটি আমার প্রথম চিন্তাও ছিল, এনএসকিএল। অবশ্যই, রফতানি ইত্যাদির ক্ষেত্রে অনেকগুলি সমস্যা রয়েছে Plus প্লাস, ওপিতে কেবল সারণি উল্লেখ করা হয়েছিল। আচ্ছা ভালো. আমি কোনও ডিবি বিশেষজ্ঞ নই, যেমনটি স্পষ্ট।
জোসেফ.বি
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.