কীভাবে একটি মাইএসকিউএল শ্রেণিবিন্যাস পুনরুদ্ধার কোয়েরি তৈরি করবেন


271

আমার একটি মাইএসকিউএল টেবিল রয়েছে যা নীচে রয়েছে:

id | name        | parent_id
19 | category1   | 0
20 | category2   | 19
21 | category3   | 20
22 | category4   | 21
......

এখন, আমি একটি একক মাইএসকিউএল কোয়েরি রাখতে চাই যাতে আমি কেবল আইডি সরবরাহ করি [উদাহরণস্বরূপ 'আইডি = 19' বলুন] তারপরে আমার তার সমস্ত শিশু আইডি পাওয়া উচিত [অর্থাত্ আইডিতে '20, 21,22 'থাকতে হবে]। ... এছাড়াও, বাচ্চাদের শ্রেণিবিন্যাস বিভিন্নভাবে জানা যায় না ...

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


মনে করুন শ্রেণিবদ্ধতা 7 স্তর গভীর। আপনি আউটপুট টেবিলটি দেখতে কেমন আশা করবেন?
জোনাথন লেফলার

1
মাইএসকিউএল (এখনও) শ্রেণিবদ্ধ প্রশ্নগুলি সমর্থন করে না (অন্যান্য আধুনিক ডিবিএমএস হিসাবে)। আপনার একটি সঞ্চিত প্রক্রিয়া লিখতে হবে বা আলাদা একটি ডেটামোডেল ব্যবহার করতে হবে।
a_horse_with_no_name


1
এমওয়াইএসকিউএল ৮.০ সিটিই (কমন সারণী এক্সপ্রেশন) ব্যবহার করে পুনরাবৃত্ত ক্যোয়ারিকে সমর্থন করবে
ইউজার 3712320

শেষ মন্তব্য আইডি থেকে শুরু পোস্টের সম্পূর্ণ তালিকা পাওয়ার বিষয়ে কী? নাকি শেষ সন্তান?
জো

উত্তর:


392

জন্য মাইএসকিউএল 8+: রিকার্সিভ ব্যবহার withসিনট্যাক্স।
জন্য মাইএসকিউএল 5.x: ব্যবহার ইনলাইন ভেরিয়েবল পথ আইডি, বা নিজের যোগদান করে।

মাইএসকিউএল 8+

with recursive cte (id, name, parent_id) as (
  select     id,
             name,
             parent_id
  from       products
  where      parent_id = 19
  union all
  select     p.id,
             p.name,
             p.parent_id
  from       products p
  inner join cte
          on p.parent_id = cte.id
)
select * from cte;

সুনির্দিষ্ট মানটি সেই পিতামাতার parent_id = 19মধ্যে সেট করা উচিত idযা আপনি সমস্ত বংশধর নির্বাচন করতে চান।

মাইএসকিউএল 5.x

মাইএসকিউএল সংস্করণগুলি যা সাধারণ টেবিল এক্সপ্রেশনগুলি সমর্থন করে না (সংস্করণ 5.7 পর্যন্ত), আপনি নিম্নলিখিত প্রশ্নের সাথে এটি অর্জন করবেন:

select  id,
        name,
        parent_id 
from    (select * from products
         order by parent_id, id) products_sorted,
        (select @pv := '19') initialisation
where   find_in_set(parent_id, @pv)
and     length(@pv := concat(@pv, ',', id))

এখানে একটি ঝাঁকুনি

এখানে, নির্দিষ্ট মানটি আপনি যে পিতামাতার সমস্ত বংশধর নির্বাচন করতে চান @pv := '19'তার idমধ্যে সেট করা উচিত ।

যদি কোনও পিতামাতার একাধিক সন্তান থাকে তবে এটিও কাজ করবে । যাইহোক, এটি প্রতিটি রেকর্ড শর্তটি পূরণ করা প্রয়োজন parent_id < id, অন্যথায় ফলাফল সম্পূর্ণ হবে না।

কোনও প্রশ্নের ভিতরে ভেরিয়েবল অ্যাসাইনমেন্ট

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

  • fromদফা প্রথম মূল্যায়ন করা হয়। সুতরাং যে যেখানে @pvআরম্ভ হয়।
  • whereদফা থেকে আহরণ ক্রমানুসারে প্রত্যেকটি রেকর্ডের জন্য মূল্যায়ন করা হয় fromalias লেখা। সুতরাং এই স্থানে কেবলমাত্র এমন শর্তাদি অন্তর্ভুক্ত করা হয় যার জন্য পিতামাতাকে ইতিমধ্যে বংশজাত গাছ হিসাবে উপস্থিত ছিল (প্রাথমিক পিতামাতার সমস্ত বংশধর ক্রমবর্ধমানভাবে যুক্ত হয়েছে @pv)।
  • এই whereধারাটির শর্তগুলি যথাযথভাবে মূল্যায়ন করা হয়, এবং মোট ফলাফল নিশ্চিত হওয়ার পরে মূল্যায়ন ব্যাহত হয়। সুতরাং দ্বিতীয় শর্তটি অবশ্যই দ্বিতীয় স্থানে থাকতে হবে, কারণ এটি idপিতামাতার তালিকায় যুক্ত করে এবং এটি কেবল তখনই ঘটে যখন idপাসগুলি প্রথম শর্তটি পাস করে। lengthফাংশন শুধুমাত্র করতে বলা হয় নিশ্চিত এই অবস্থা সবসময় সত্য, এমনকি যদি pvস্ট্রিং কিছু কারণে একটি falsy মান উত্পাদ হবে।

সব মিলিয়ে, কেউ এই অনুমানগুলি নির্ভর করতে খুব ঝুঁকিপূর্ণ খুঁজে পেতে পারে। ডকুমেন্টেশন সাবধান করে:

আপনি প্রত্যাশিত ফলাফল পেতে পারেন, তবে এটির নিশ্চয়তা নেই [...] ব্যবহারকারীর ভেরিয়েবলগুলির সাথে জড়িত এক্সপ্রেশনগুলির জন্য মূল্যায়নের ক্রমটি অপরিবর্তিত।

সুতরাং এটি উপরোক্ত ক্যোয়ারির সাথে ধারাবাহিকভাবে কাজ করলেও, মূল্যায়নের ক্রমটি এখনও পরিবর্তিত হতে পারে, উদাহরণস্বরূপ আপনি যখন শর্ত যুক্ত করেন বা একটি বৃহত্তর ক্যোয়ারিতে ভিউ বা উপ-কোয়েরি হিসাবে এই কোয়েরিটি ব্যবহার করেন। এটি এমন একটি "বৈশিষ্ট্য" যা ভবিষ্যতে মাইএসকিউএল প্রকাশে মুছে ফেলা হবে :

মাইএসকিউএল এর পূর্ববর্তী রিলিজগুলি ছাড়াও বিবৃতিতে কোনও ব্যবহারকারী ভেরিয়েবলের একটি মান নির্ধারণ করা সম্ভব করে SET। এই কার্যকারিতাটি MySQL 8.0 এ পশ্চাদপটে সামঞ্জস্যের জন্য সমর্থিত তবে মাইএসকিউএল এর ভবিষ্যতে প্রকাশে অপসারণের সাপেক্ষে।

উপরে উল্লিখিত হিসাবে, মাইএসকিউএল 8.0 থেকে আপনার পুনরাবৃত্ত withসিনট্যাক্স ব্যবহার করা উচিত ।

দক্ষতা

খুব বড় ডেটা সেটগুলির জন্য এই সমাধানটি ধীর হয়ে যেতে পারে, কারণ find_in_setঅপারেশন কোনও তালিকার কোনও নম্বর সন্ধানের সবচেয়ে আদর্শ উপায় নয়, অবশ্যই কোনও তালিকায় নয় যা রেকর্ডের সংখ্যার সাথে একই পরিমাণে আকারে পৌঁছায় records

বিকল্প 1: with recursive,connect by

আরো অনেক বেশী ডাটাবেস বাস্তবায়ন এসকিউএল: 1999 ISO- র মান WITH [RECURSIVE]সিনট্যাক্স রিকার্সিভ জিজ্ঞাসার জন্য (যেমন Postgres 8.4+ , এসকিউএল সার্ভার 2005+ , DB2 , ওরাকল 11gR2 + + , SQLite 3.8.4+ , Firebird 2.1 + -এর , ও H2 , HyperSQL 2.1.0+ , Teradata , মারিয়াডিবি 10.2.2+ )। আর যেমন সংস্করণ 8.0, এছাড়াও মাইএসকিউএল এটি সমর্থন । সিনট্যাক্সটি ব্যবহারের জন্য এই উত্তরের শীর্ষটি দেখুন।

কিছু ডাটাবেস যেমন হায়ারারকিকাল বর্ণন আপগুলি জন্য একটি বিকল্প, অ-মানক সিনট্যাক্স আছে CONNECT BYউপর দফা প্রাপ্তিসাধ্য ওরাকল , DB2 , Informix , CUBRID এবং অন্যান্য ডাটাবেস।

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

বিকল্প 2: পাথ-শৈলীর শনাক্তকারী

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

ID       | NAME
19       | category1   
19/1     | category2  
19/1/1   | category3  
19/1/1/1 | category4  

তারপরে আপনার selectচেহারাটি এমন দেখাবে:

select  id,
        name 
from    products
where   id like '19/%'

বিকল্প 3: পুনরাবৃত্তি স্ব-যোগ দেয়

আপনার শ্রেণিবিন্যাস গাছটি কত গভীর হতে পারে তার যদি আপনি একটি উচ্চতর সীমাটি জানেন তবে আপনি sqlএই জাতীয় মানের কোয়েরি ব্যবহার করতে পারেন :

select      p6.parent_id as parent6_id,
            p5.parent_id as parent5_id,
            p4.parent_id as parent4_id,
            p3.parent_id as parent3_id,
            p2.parent_id as parent2_id,
            p1.parent_id as parent_id,
            p1.id as product_id,
            p1.name
from        products p1
left join   products p2 on p2.id = p1.parent_id 
left join   products p3 on p3.id = p2.parent_id 
left join   products p4 on p4.id = p3.parent_id  
left join   products p5 on p5.id = p4.parent_id  
left join   products p6 on p6.id = p5.parent_id
where       19 in (p1.parent_id, 
                   p2.parent_id, 
                   p3.parent_id, 
                   p4.parent_id, 
                   p5.parent_id, 
                   p6.parent_id) 
order       by 1, 2, 3, 4, 5, 6, 7;

এই ঝাঁকুনি দেখুন

whereশর্ত নির্দিষ্ট করে যা পিতা বা মাতা আপনি উত্তরপুরুষ উদ্ধার করতে চান। আপনি প্রয়োজন হিসাবে আরও স্তরের সাথে এই কোয়েরি প্রসারিত করতে পারেন।


26
আমি আপনার ব্যাখ্যা পছন্দ। এটি কেবল কোনও উত্তর দেয় না, এটি ব্যাখ্যা করে যে এটি কেন সমস্যার সমাধান করে যাতে আমরা আসলে এটি থেকে শিখতে পারি। সম্পাদনা: এটিও দুর্দান্ত যে এটি আগে থেকেই স্তরের সংখ্যা জানার উপর নির্ভর করে না।
বাইসন

1
@ বাইসন, আমি আপনার ফিড-ব্যাককে অনেক ধন্যবাদ জানাই। ধন্যবাদ!
ট্রিনকোট

2
@ Avion, এটা কিছু আপনি কোথাও দিতে হবে না, এটা একটি হল প্রয়োজন যে সব রেকর্ডের জন্য এই শর্ত সত্য। আপনার যদি এক বা একাধিক রেকর্ড থাকে parent_id > idতবে আপনি এই সমাধানটি ব্যবহার করতে পারবেন না।
ট্রিনকোট

2
যে কেউ এই WITH RECURSIVEপদ্ধতিটি ব্যবহার করতে চাইছেন , আমি নীচের নিবন্ধটি বিভিন্ন পরিস্থিতিতে যেমন পুনরাবৃত্তির গভীরতা, স্বতন্ত্রতা এবং চক্র সনাক্তকরণ এবং বন্ধ করার মতো সত্যিকারের সাহায্যে পেয়েছি
ঘোড়া

2
আমি আমার কম্পিউটারে মাইএসকিউএল ৫. on-এর মূল সমাধানটি আমার নিজের টেবিলগুলিতে চেষ্টা করেছি, কিন্তু @pv: = কনট্যাট (@ পিভি, ',', আইডি) এর সমমানের কারণে এটি মিথ্যাতে মূল্যায়ন করে না। আমি এটিকে দৈর্ঘ্য (@pv: = concat (@pv, ',', id))> 0 এ পরিবর্তন করে এটি ঠিক করেছি যাতে এটি সর্বদা সত্য।
কেসি ওং

82

মাইএসকিউএল-এ হায়ারার্কিকাল ডেটা পরিচালনা করা ব্লগ থেকে

টেবিল কাঠামো

+-------------+----------------------+--------+
| 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 |
+-------------+----------------------+--------+

প্রশ্ন:

SELECT t1.name AS lev1, t2.name as lev2, t3.name as lev3, t4.name as lev4
FROM category AS t1
LEFT JOIN category AS t2 ON t2.parent = t1.category_id
LEFT JOIN category AS t3 ON t3.parent = t2.category_id
LEFT JOIN category AS t4 ON t4.parent = t3.category_id
WHERE t1.name = 'ELECTRONICS';

আউটপুট

+-------------+----------------------+--------------+-------+
| lev1        | lev2                 | lev3         | lev4  |
+-------------+----------------------+--------------+-------+
| ELECTRONICS | TELEVISIONS          | TUBE         | NULL  |
| ELECTRONICS | TELEVISIONS          | LCD          | NULL  |
| ELECTRONICS | TELEVISIONS          | PLASMA       | NULL  |
| ELECTRONICS | PORTABLE ELECTRONICS | MP3 PLAYERS  | FLASH |
| ELECTRONICS | PORTABLE ELECTRONICS | CD PLAYERS   | NULL  |
| ELECTRONICS | PORTABLE ELECTRONICS | 2 WAY RADIOS | NULL  |
+-------------+----------------------+--------------+-------+

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

বিস্তারিত জানতে ব্লগটি দেখুন fer

সম্পাদনা করুন:

select @pv:=category_id as category_id, name, parent from category
join
(select @pv:=19)tmp
where parent=@pv

আউটপুট:

category_id name    parent
19  category1   0
20  category2   19
21  category3   20
22  category4   21

রেফারেন্স: মাইএসকিএলে পুনঃবৃদ্ধিযোগ্য নির্বাচন কীভাবে করবেন?


23
হাইয়ারার্কিতে সর্বাধিক 4 টি স্তরের বেশি না হওয়া পর্যন্ত এটি ঠিক আছে। যদি এন স্তর রয়েছে তবে সঠিকভাবে ক্যোয়ারী তৈরি করতে আপনার এটি জানতে হবে।
জোনাথন লেফলার

2
@ দামোদরন, আপনার জবাবের জন্য ধন্যবাদ ... আমার যা দরকার ছিল তা হল এমন একটি শর্ত যেখানে বাচ্চার সংখ্যা জানা যায় না ... এবং যে ব্লগে অন্তর্নির্মিত ধারণাটি ব্যবহার করা হয় তাতে হায়ারার্কিটি জানা দরকার যা কোনটি নয় আমার ক্ষেত্রে ... সুতরাং আমাকে আপনার মতামতটিও একইরূপে জানাও ... সুতরাং, সহজ কথায় বলতে গেলে 'এন' হায়রেরেচি স্তরগুলি যেখানে 'এন' জানা যায় না তা পরিচালনা করার জন্য আমার একটি প্রশ্ন প্রয়োজন .....
তরুণ পার্সওয়ানি

1
@ ব্যবহারকারী 3036105: একটি একক এসকিউএল কোয়েরি দিয়ে মাইএসকিউএলে এটি করা সম্ভব নয় । মাইএসকিউএল কেবল তার জন্য যথেষ্ট উন্নত নয়। আপনার যদি সত্যিই এটির প্রয়োজন হয়, এমন একটি ডিবিএমএসে আপগ্রেড করার কথা বিবেচনা করুন যা পুনরাবৃত্ত অনুসন্ধানগুলি সমর্থন করে।
a_horse_with_no_name

5
> বেশিরভাগ ব্যবহারকারীর এক সময় বা অন্য কোনও এসকিউএল ডাটাবেসে হায়ারার্কিকাল ডেটা নিয়ে কাজ করা হয়েছিল এবং সন্দেহ নেই যে শিখেছে যে শ্রেণিবিন্যাসের ডেটা পরিচালনার কোনও সম্পর্কযুক্ত ডাটাবেসের জন্য নয়। হতে পারে আপনি একটি মাইএসকিউএল ডাটাবেস বোঝাতে চেয়েছিলেন। একটি ওরাকল ডাটাবেস হায়ারারিকাল ডেটা এবং কোয়েরিগুলি বেশ ভাল পরিচালনা করে।
পিটার নসকো

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

9

এগুলি চেষ্টা করুন:

সারণির সংজ্ঞা:

DROP TABLE IF EXISTS category;
CREATE TABLE category (
    id INT AUTO_INCREMENT PRIMARY KEY,
    name VARCHAR(20),
    parent_id INT,
    CONSTRAINT fk_category_parent FOREIGN KEY (parent_id)
    REFERENCES category (id)
) engine=innodb;

পরীক্ষামূলক সারি:

INSERT INTO category VALUES
(19, 'category1', NULL),
(20, 'category2', 19),
(21, 'category3', 20),
(22, 'category4', 21),
(23, 'categoryA', 19),
(24, 'categoryB', 23),
(25, 'categoryC', 23),
(26, 'categoryD', 24);

পুনরাবৃত্তির সঞ্চিত পদ্ধতি:

DROP PROCEDURE IF EXISTS getpath;
DELIMITER $$
CREATE PROCEDURE getpath(IN cat_id INT, OUT path TEXT)
BEGIN
    DECLARE catname VARCHAR(20);
    DECLARE temppath TEXT;
    DECLARE tempparent INT;
    SET max_sp_recursion_depth = 255;
    SELECT name, parent_id FROM category WHERE id=cat_id INTO catname, tempparent;
    IF tempparent IS NULL
    THEN
        SET path = catname;
    ELSE
        CALL getpath(tempparent, temppath);
        SET path = CONCAT(temppath, '/', catname);
    END IF;
END$$
DELIMITER ;

সঞ্চিত পদ্ধতির জন্য মোড়ক ফাংশন:

DROP FUNCTION IF EXISTS getpath;
DELIMITER $$
CREATE FUNCTION getpath(cat_id INT) RETURNS TEXT DETERMINISTIC
BEGIN
    DECLARE res TEXT;
    CALL getpath(cat_id, res);
    RETURN res;
END$$
DELIMITER ;

উদাহরণ নির্বাচন করুন:

SELECT id, name, getpath(id) AS path FROM category;

আউটপুট:

+----+-----------+-----------------------------------------+
| id | name      | path                                    |
+----+-----------+-----------------------------------------+
| 19 | category1 | category1                               |
| 20 | category2 | category1/category2                     |
| 21 | category3 | category1/category2/category3           |
| 22 | category4 | category1/category2/category3/category4 |
| 23 | categoryA | category1/categoryA                     |
| 24 | categoryB | category1/categoryA/categoryB           |
| 25 | categoryC | category1/categoryA/categoryC           |
| 26 | categoryD | category1/categoryA/categoryB/categoryD |
+----+-----------+-----------------------------------------+

নির্দিষ্ট পাথ দিয়ে সারি ফিল্টারিং:

SELECT id, name, getpath(id) AS path FROM category HAVING path LIKE 'category1/category2%';

আউটপুট:

+----+-----------+-----------------------------------------+
| id | name      | path                                    |
+----+-----------+-----------------------------------------+
| 20 | category2 | category1/category2                     |
| 21 | category3 | category1/category2/category3           |
| 22 | category4 | category1/category2/category3/category4 |
+----+-----------+-----------------------------------------+

1
এটি তখন এক সন্তানের বেশি কাজ করবে না। যেমন(20, 'category2', 19), (21, 'category3', 20), (22, 'category4', 20),
ক্লিন কোড

3
আমি নিশ্চিত যে এটি একাধিক শিশুর জন্য কাজ করে। এমনকি আমি এটি আবার পরীক্ষাও করেছি।
ফান্দি সুসান্টো

@ ফান্দি সুসান্টো, ধন্যবাদ এটি আমার পক্ষে অনেকটাই সহায়তা করে।
ডোগান ওজার

9

আমি যে সর্বোত্তম পন্থা নিয়ে এসেছি তা হ'ল

  1. গাছ সন্ধান \ বাছাই store সংরক্ষণ করতে বংশ ব্যবহার করুন। এটি পর্যাপ্ত পরিমাণে বেশি এবং অন্য যে কোনও পদ্ধতির চেয়ে পড়ার জন্য হাজার গুণ দ্রুত কাজ করে। এটি ডিবি পরিবর্তিত হয়েও সেই ধাঁচে থাকতে দেয় (যে কোনও ডিবি সেই ধরণটি ব্যবহার করার অনুমতি দেবে)
  2. নির্দিষ্ট আইডির জন্য বংশ নির্ধারণ করে এমন ফাংশন ব্যবহার করুন।
  3. এটি আপনার ইচ্ছামত ব্যবহার করুন (নির্বাচন করুন বা সিইউডি অপারেশনে বা এমনকি চাকরির মাধ্যমে)।

বংশের পদ্ধতির descr। উদাহরণস্বরূপ এখানে বা এখানে যেখানেই পাওয়া যাবে । ফাংশন হিসাবে - যে আমাকে প্ররোচিত।

শেষ পর্যন্ত - আরও বা কম-সহজ, অপেক্ষাকৃত দ্রুত এবং সিম্পল সমাধান পেয়েছে।

ফাংশন এর শরীর

-- --------------------------------------------------------------------------------
-- Routine DDL
-- Note: comments before and after the routine body will not be stored by the server
-- --------------------------------------------------------------------------------
DELIMITER $$

CREATE DEFINER=`root`@`localhost` FUNCTION `get_lineage`(the_id INT) RETURNS text CHARSET utf8
    READS SQL DATA
BEGIN

 DECLARE v_rec INT DEFAULT 0;

 DECLARE done INT DEFAULT FALSE;
 DECLARE v_res text DEFAULT '';
 DECLARE v_papa int;
 DECLARE v_papa_papa int DEFAULT -1;
 DECLARE csr CURSOR FOR 
  select _id,parent_id -- @n:=@n+1 as rownum,T1.* 
  from 
    (SELECT @r AS _id,
        (SELECT @r := table_parent_id FROM table WHERE table_id = _id) AS parent_id,
        @l := @l + 1 AS lvl
    FROM
        (SELECT @r := the_id, @l := 0,@n:=0) vars,
        table m
    WHERE @r <> 0
    ) T1
    where T1.parent_id is not null
 ORDER BY T1.lvl DESC;
 DECLARE CONTINUE HANDLER FOR NOT FOUND SET done = TRUE;
    open csr;
    read_loop: LOOP
    fetch csr into v_papa,v_papa_papa;
        SET v_rec = v_rec+1;
        IF done THEN
            LEAVE read_loop;
        END IF;
        -- add first
        IF v_rec = 1 THEN
            SET v_res = v_papa_papa;
        END IF;
        SET v_res = CONCAT(v_res,'-',v_papa);
    END LOOP;
    close csr;
    return v_res;
END

এবং তারপর আপনি ঠিক

select get_lineage(the_id)

আশা করি এটি কাউকে সাহায্য করবে :)


9

এখানে অন্য একটি সারি জন্য একই কাজ

মাইএসকিউএল পুনরাবৃত্তিকে নির্বাচন করুন একাধিক স্তরের সমস্ত শিশুকে পান

ক্যোয়ারীটি হ'ল:

SELECT GROUP_CONCAT(lv SEPARATOR ',') FROM (
  SELECT @pv:=(
    SELECT GROUP_CONCAT(id SEPARATOR ',')
    FROM table WHERE parent_id IN (@pv)
  ) AS lv FROM table 
  JOIN
  (SELECT @pv:=1)tmp
  WHERE parent_id IN (@pv)
) a;

এটা আমরা কিভাবে করতে পারি? SELECT idFolder, (SELECT GROUP_CONCAT(lv SEPARATOR ',') FROM ( SELECT @pv:=(SELECT GROUP_CONCAT(idFolder SEPARATOR ',') FROM Folder WHERE idFolderParent IN (@pv)) AS lv FROM Folder JOIN (SELECT @pv:= F1.idFolder )tmp WHERE idFolderParent IN (@pv)) a) from folder F1 where id > 10; আমি @pv- এর জন্য F1.idFolder উল্লেখ করতে পারি না
রাহুল

আমি ওপির মূল প্রশ্নটি তাদের মন্তব্যে প্রদর্শিত ডেটা দিয়ে টেবিলটি পুনরায় তৈরি করেছি, তারপরে আপনার ক্যোয়ারীটি এখানে চালিয়েছি এবং NULLফলস্বরূপ একটি একক পেয়েছি । আপনি কি জানেন যে কেন হতে পারে? ডাটাবেস ইঞ্জিনের শর্তে কি পূর্বশর্ত রয়েছে, বা আপনি এই উত্তরটি তৈরি করেছেন যেহেতু এই কোয়েরিকে পুরানো হয়ে গেছে?
ডিজিটাল নিনজা

7

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

ancestor | descendant | depth
0        | 0          | 0
0        | 19         | 1
0        | 20         | 2
0        | 21         | 3
0        | 22         | 4
19       | 19         | 0
19       | 20         | 1
19       | 21         | 3
19       | 22         | 4
20       | 20         | 0
20       | 21         | 1
20       | 22         | 2
21       | 21         | 0
21       | 22         | 1
22       | 22         | 0

আপনার এই টেবিলটি হয়ে গেলে, শ্রেণিবদ্ধ প্রশ্নগুলি খুব সহজ এবং দ্রুত হয়ে যায়। 20 বিভাগের সমস্ত বংশধর পেতে:

SELECT cat.* FROM categories_closure AS cl
INNER JOIN categories AS cat ON cat.id = cl.descendant
WHERE cl.ancestor = 20 AND cl.depth > 0

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

সম্পাদনা : প্রশ্নটি দেখুন একটি সম্পর্কিত ডেটাবেজে শ্রেণিবদ্ধ তথ্য সংরক্ষণের বিকল্পগুলি কী কী? আরও বিকল্পের জন্য। বিভিন্ন পরিস্থিতিতে বিভিন্ন অনুকূল সমাধান রয়েছে।


4

সন্তানের প্রথম পুনরাবৃত্তির তালিকা তৈরি করার সহজ প্রশ্ন:

select @pv:=id as id, name, parent_id
from products
join (select @pv:=19)tmp
where parent_id=@pv

ফলাফল:

id  name        parent_id
20  category2   19
21  category3   20
22  category4   21
26  category24  22

... বাম যোগ দিয়ে:

select
    @pv:=p1.id as id
  , p2.name as parent_name
  , p1.name name
  , p1.parent_id
from products p1
join (select @pv:=19)tmp
left join products p2 on p2.id=p1.parent_id -- optional join to get parent name
where p1.parent_id=@pv

সমস্ত সন্তানের তালিকা তৈরি করার জন্য @ টিনকোটের সমাধান:

select  id,
        name,
        parent_id 
from    (select * from products
         order by parent_id, id) products_sorted,
        (select @pv := '19') initialisation
where   find_in_set(parent_id, @pv) > 0
and     @pv := concat(@pv, ',', id)

এটি এসকিএল ফিডল দিয়ে অনলাইনে পরীক্ষা করুন এবং সমস্ত ফলাফল দেখুন।

http://sqlfiddle.com/#!9/a318e3/4/0


3

আপনি এটি অন্য ডেটাবেজে এটি সহজেই পুনরাবৃত্তির ক্যোয়ারী (পারফরম্যান্সে ওয়াইএমএমভি) দিয়ে করতে পারেন।

এটি করার অন্য উপায়টি হ'ল দুটি অতিরিক্ত বিট ডেটা, একটি বাম এবং ডান মান store বাম এবং ডান মানটি আপনি যে গাছের কাঠামোর প্রতিনিধিত্ব করছেন তার প্রাক-অর্ডার ট্রভারসাল থেকে প্রাপ্ত।

এটি পরিবর্তিত প্রাক অর্ডার ট্রি ট্রভারসাল হিসাবে পরিচিত এবং আপনাকে একবারে সমস্ত পিতামাতার মানগুলি পেতে একটি সাধারণ ক্যোয়ারী চালাতে দেয়। এটি "নেস্টেড সেট" নামেও যায়।


আমি আপনার সাথে একটি অনুরূপ মন্তব্য যুক্ত করতে চেয়েছিলাম, তবে যেহেতু আপনি এটি করেছেন, আমি "নেস্টেড সেট" এর একটি ভাল উদাহরণের জন্য কেবল একটি লিঙ্ক যুক্ত করব: মাইকিহিলিয়ার
মিরোস্লা ওপোকা

2

মাইএসকিএলে স্ব-সম্পর্কের টেবিলের গাছ তৈরি করতে কেবল ব্লুএম / ট্রি পিএইচপি ক্লাস ব্যবহার করুন।

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

এখানে ব্লুএম / ট্রি ব্যবহারের উদাহরণ রয়েছে:

<?php 
require '/path/to/vendor/autoload.php'; $db = new PDO(...); // Set up your database connection 
$stm = $db->query('SELECT id, parent, title FROM tablename ORDER BY title'); 
$records = $stm->fetchAll(PDO::FETCH_ASSOC); 
$tree = new BlueM\Tree($records); 
...

2

এখানে চিত্র বর্ণনা লিখুন

এটি একটি বিভাগের টেবিল।

SELECT  id,
        NAME,
        parent_category 
FROM    (SELECT * FROM category
         ORDER BY parent_category, id) products_sorted,
        (SELECT @pv := '2') initialisation
WHERE   FIND_IN_SET(parent_category, @pv) > 0
AND     @pv := CONCAT(@pv, ',', id)

আউটপুট :: এখানে চিত্র বর্ণনা লিখুন


1
আপনি এই ব্যাখ্যা করতে পারেন? তবে আমি গ্যারান্টি দিচ্ছি যে এটি কাজ করছে। ধন্যবাদ.
wobsoriano

1
plz কোয়েরিটি ব্যাখ্যা করুন এবং @pv এর অর্থ কী ?? এই ক্যোয়ারীতে লুপ কীভাবে কাজ করছে?
আমানজোট কৌর

2
মনে হয় না যে সমস্ত স্তরে বাচ্চাদের আইডি থাকলে তাদের বাবা-মার চেয়ে কম থাকে। :(
জোনাস

1
@ জোনাস বিভিন্ন সংমিশ্রণের চেষ্টা করে আসল সমস্যাটি সনাক্ত করতে আমাকে 20 মিনিট সময় নিয়েছিল। হ্যাঁ আপনি ঠিক. এটি এর প্যারেন্ট আইডির চেয়ে কম আইডি দিয়ে কাজ করবে না। আপনার কি কোন সমাধান আছে?
মোয়াজ

@ মুয়াজ আমি অবশেষে এটি একটি "পথ" ক্ষেত্রটি ব্যবহার করে সমাধান করেছি যার মধ্যে সম্পর্কিত সারির জন্য পথ রয়েছে, যেমন আইডি 577 সহ সারিটির পথ রয়েছে "/ 1/2/45/577 /"। আপনি যদি আইডি 2 এর সমস্ত বাচ্চাদের সন্ধান করেন তবে আপনি "/ 1/2 /%" লাইক দিয়ে সমস্ত সারিটি নির্বাচন করতে পারেন। কেবলমাত্র খারাপ দিকটি হ'ল আপনাকে আপনার আপডেট পদ্ধতিগুলিতে পাথগুলি আপডেট করতে হবে। তবে মাইএসকিউএল 5.6 (সামঞ্জস্যপূর্ণ) এর জন্য, এটি আমার জন্য কাজ করা একমাত্র সমাধান ছিল।
জোনাস

1

এটি কিছুটা জটিল, এটি আপনার পক্ষে কাজ করছে কিনা তা পরীক্ষা করে দেখুন

select a.id,if(a.parent = 0,@varw:=concat(a.id,','),@varw:=concat(a.id,',',@varw)) as list from (select * from recursivejoin order by if(parent=0,id,parent) asc) a left join recursivejoin b on (a.id = b.parent),(select @varw:='') as c  having list like '%19,%';

এসকিউএল ফিডল লিংক http://www.sqlfiddle.com/#!2/e3cdf/2

আপনার ক্ষেত্র এবং টেবিলের নামটি যথাযথভাবে প্রতিস্থাপন করুন।


এই ক্ষেত্রে এটি কাজ করবে না sqlfiddle.com/#!2/19360/2 , এই কৌশলটি দিয়ে, কমপক্ষে আপনার প্রথমে স্তরক্রমিক স্তরের অর্ডার করা উচিত।
জওগার চ্যাং

1

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

কিছু মত:

id | name        | path
19 | category1   | /19
20 | category2   | /19/20
21 | category3   | /19/20/21
22 | category4   | /19/20/21/22

উদাহরণ:

-- get children of category3:
SELECT * FROM my_table WHERE path LIKE '/19/20/21%'
-- Reparent an item:
UPDATE my_table SET path = REPLACE(path, '/19/20', '/15/16') WHERE path LIKE '/19/20/%'

পাথের দৈর্ঘ্য এবং ORDER BY pathবেস 36 এনকোডিং এর পরিবর্তে আসল সংখ্যার পাথ আইডি ব্যবহার করুন

 // base10 => base36
 '1' => '1',
 '10' => 'A',
 '100' => '2S',
 '1000' => 'RS',
 '10000' => '7PS',
 '100000' => '255S',
 '1000000' => 'LFLS',
 '1000000000' => 'GJDGXS',
 '1000000000000' => 'CRE66I9S'

https://en.wikipedia.org/wiki/Base36

এনকোডড আইডিতে নির্দিষ্ট দৈর্ঘ্য এবং প্যাডিং ব্যবহার করে স্ল্যাশ '/' বিভাজককেও দমন করা

বিশদ অপ্টিমাইজেশনের ব্যাখ্যা এখানে: https://bojanz.wordpress.com/2014/04/25/storing-hierarchical-data-matoryized-path/

করতে

একটি আইটেমের retreive পূর্বপুরুষদের জন্য পথ বিভক্ত ফাংশন বা পদ্ধতি নির্মাণ


ধন্যবাদ! আকর্ষণীয়base36
ভ্লাদ

0

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

SET @id:= '22';

SELECT Menu_Name, (@id:=Sub_Menu_ID ) as Sub_Menu_ID, Menu_ID 
FROM 
    ( SELECT Menu_ID, Menu_Name, Sub_Menu_ID 
      FROM menu 
      ORDER BY Sub_Menu_ID DESC
    ) AS aux_table 
    WHERE Menu_ID = @id
     ORDER BY Sub_Menu_ID;

তাদের
স্ত্রীর

-1

আমি এটি আরও সহজে পেয়েছি:

1) এমন একটি ফাংশন তৈরি করুন যা পরীক্ষা করবে যে কোনও আইটেমি অন্যের পৈতৃক শ্রেণিবিন্যাসের কোথাও আছে কিনা। এর মতো কিছু (আমি ফাংশনটি লিখব না, WHOL কর দিয়ে তৈরি করব):

is_related(id, parent_id);

আপনার উদাহরণে

is_related(21, 19) == 1;
is_related(20, 19) == 1;
is_related(21, 18) == 0;

২) উপ-নির্বাচন ব্যবহার করুন, এরকম কিছু:

select ...
from table t
join table pt on pt.id in (select i.id from table i where is_related(t.id,i.id));

-1

আমি আপনার জন্য একটি প্রশ্ন তৈরি করেছি। এটি আপনাকে একক ক্যোয়ারির সাথে পুনরাবৃত্ত বিভাগে দেবে:

SELECT id,NAME,'' AS subName,'' AS subsubName,'' AS subsubsubName FROM Table1 WHERE prent is NULL
UNION 
SELECT b.id,a.name,b.name AS subName,'' AS subsubName,'' AS subsubsubName FROM Table1 AS a LEFT JOIN Table1 AS b ON b.prent=a.id WHERE a.prent is NULL AND b.name IS NOT NULL 
UNION 
SELECT c.id,a.name,b.name AS subName,c.name AS subsubName,'' AS subsubsubName FROM Table1 AS a LEFT JOIN Table1 AS b ON b.prent=a.id LEFT JOIN Table1 AS c ON c.prent=b.id WHERE a.prent is NULL AND c.name IS NOT NULL 
UNION 
SELECT d.id,a.name,b.name AS subName,c.name AS subsubName,d.name AS subsubsubName FROM Table1 AS a LEFT JOIN Table1 AS b ON b.prent=a.id LEFT JOIN Table1 AS c ON c.prent=b.id LEFT JOIN Table1 AS d ON d.prent=c.id WHERE a.prent is NULL AND d.name IS NOT NULL 
ORDER BY NAME,subName,subsubName,subsubsubName

এখানে একটি ঝাঁকুনি


আপনার ইতিবাচক খ্যাতি ফিরে পেতে দয়া করে আপনার উত্তর মুছুন / সম্পাদনা করুন।
fWd82
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.