catatan: pertanyaan ini telah diperbarui untuk mencerminkan bahwa kita saat ini menggunakan MySQL, setelah melakukannya, saya ingin melihat seberapa mudahnya jika kita beralih ke basis data pendukung CTE.
Saya memiliki tabel referensi sendiri dengan kunci utama, id
dan kunci asing parent_id
.
+------------+--------------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+------------+--------------+------+-----+---------+----------------+
| id | int(11) | NO | PRI | NULL | auto_increment |
| parent_id | int(11) | YES | | NULL | |
| name | varchar(255) | YES | | NULL | |
| notes | text | YES | | NULL | |
+------------+--------------+------+-----+---------+----------------+
Diberikan name
, bagaimana saya bisa meminta orang tua tingkat atas?
Diberikan name
, bagaimana saya bisa meminta semua yang id
terkait dengan catatan name = 'foo'
?
konteks: Saya bukan dba, tetapi saya berencana untuk meminta dba untuk menerapkan jenis struktur hierarkis ini dan ingin menguji beberapa pertanyaan. Motivasi untuk melakukannya dijelaskan oleh Kattge et al 2011 .
Berikut adalah contoh hubungan antar id dalam tabel:
-- -----------------------------------------------------
-- Create a new database called 'testdb'
-- -----------------------------------------------------
SET @OLD_UNIQUE_CHECKS=@@UNIQUE_CHECKS, UNIQUE_CHECKS=0;
SET @OLD_FOREIGN_KEY_CHECKS=@@FOREIGN_KEY_CHECKS, FOREIGN_KEY_CHECKS=0;
SET @OLD_SQL_MODE=@@SQL_MODE, SQL_MODE='TRADITIONAL';
CREATE SCHEMA IF NOT EXISTS `testdb` DEFAULT CHARACTER SET latin1 COLLATE latin1_swedish_ci ;
USE `testdb` ;
-- -----------------------------------------------------
-- Table `testdb`.`observations`
-- -----------------------------------------------------
CREATE TABLE IF NOT EXISTS `testdb`.`observations` (
`id` INT NOT NULL ,
`parent_id` INT NULL ,
`name` VARCHAR(45) NULL ,
PRIMARY KEY (`id`) )
ENGINE = InnoDB;
SET SQL_MODE=@OLD_SQL_MODE;
SET FOREIGN_KEY_CHECKS=@OLD_FOREIGN_KEY_CHECKS;
SET UNIQUE_CHECKS=@OLD_UNIQUE_CHECKS;
-- -----------------------------------------------------
-- Add Example Data Set
-- -----------------------------------------------------
INSERT INTO observations VALUES (1,3), (2,5), (3,NULL), (4,10),
(5,NULL), (6,1), (7,5), (8,10), (9,10), (10,3);
mysql
postgresql
hierarchy
David LeBauer
sumber
sumber
Jawaban:
Anda pasti harus menulis skrip ini melalui Bahasa Prosedur yang Disimpan MySQL
Ini adalah Fungsi Tersimpan yang dipanggil
GetParentIDByID
untuk Mengambil ParentID yang diberi ID untuk DicariBerikut ini adalah Fungsi Tersimpan yang dipanggil
GetAncestry
untuk Mengambil Daftar ParentID mulai dari Generasi Pertama, semua hierarki diberi ID untuk memulai dengan:Ini adalah sesuatu untuk menghasilkan data sampel:
Inilah yang dihasilkannya:
Berikut adalah fungsi yang dihasilkan untuk setiap nilai:
MORAL OF THE STORY: Pengambilan data rekursif harus ditulis dalam MySQL
UPDATE 2011-10-24 17:17 EDT
Ini adalah kebalikan dari GetAncestry. Saya menyebutnya GetFamilyTree.
Berikut algoritanya:
Saya percaya dari kelas Struktur Data dan Algoritma saya di College, ini disebut sesuatu seperti preorder / prefix tree traversal.
Ini kodenya:
Inilah yang dihasilkan setiap baris
Algoritma ini berfungsi dengan baik asalkan tidak ada jalur siklik. Jika ada jalur siklik, Anda harus menambahkan kolom 'dikunjungi' ke tabel.
Setelah Anda menambahkan kolom yang dikunjungi, berikut adalah algoritma yang memblokir hubungan siklik:
UPDATE 2011-10-24 17:37 EDT
Saya membuat tabel baru yang disebut pengamatan dan mengisi data sampel Anda. Saya mengubah prosedur yang tersimpan untuk menggunakan pengamatan, bukan yang bisa diprediksi. Ini output Anda:
UPDATE 2011-10-24 18:22 EDT
Saya mengubah kode untuk GetAncestry. Ada
WHILE ch > 1
itu harusWHILE ch > 0
Coba sekarang !!!
sumber
Mendapatkan semua orang tua dari simpul tertentu:
Untuk mendapatkan simpul root, Anda bisa mis
ORDER BY level
dan mengambil baris pertamaMendapatkan semua anak dari simpul tertentu:
(perhatikan kondisi swap untuk bergabung di bagian rekursif dari pernyataan)
Setahu saya, DBMS berikut mendukung CTE rekursif:
Sunting
Berdasarkan data sampel Anda, berikut ini akan mengambil semua subtrees dari tabel termasuk jalur lengkap untuk setiap node sebagai kolom tambahan:
Outputnya akan seperti ini:
sumber
Fungsi GetFamilyTree dalam jawaban Rolando tidak berfungsi ketika id yang diberikan lebih dari 4 bilangan bulat, karena fungsi FORMAT MySQL menambahkan koma untuk ribuan pemisah. Saya telah memodifikasi fungsi tersimpan GetFamilyTree untuk bekerja dengan id integer besar seperti di bawah ini:
front_id didefinisikan di dalam jika lingkaran lagi.
sumber