Bir hiyerarşi içinde Orphaned Öğeleri Kaldır

5 Cevap php

Ben bir sütun "parent_id" ile bağlı MySQL öğelerin bir listesi var.

Id, adı, parent_id: en sütunlar varsayalım

Benim kullanıcı bir hiyerarşisinde yüksek bir öğeyi siler, ben tüm çocukların silmek gerekir. Yani, iki parçalı bir soru:

1) üst artık mevcut tüm öğeler için kimlikleri dönecektir etkin ve verimli bir MySQL çağrı var mı?

2) PHP, ben bir diziye MySQL bu yetim kimlikleri alabilirsiniz düşünüyorum, sonra bir foreach döngü çalıştırmak ve her birini silmek?

Yardımlarınız için çok teşekkürler.

5 Cevap

Ben ne orijinal yazarın aklındaki hiyerarşik sorguları hatlarında bir şey oldu sanırım.

Ne yazık ki, MySQL hiyerarşik sorguları için yerel destek var (, aksine siz CONNECT BY ne istediğinizi elde etmek için kullanabilirsiniz, örneğin Oracle, için). Değil

Muhtemelen tüm yetimlere kaldırmak için en kolay yolu gibi bir sorguyu yürütmek olacaktır:

  SELECT t1.id 
    FROM table t1
      LEFT JOIN table t2 ON t2.id = t1.parent_id
    WHERE t2.id IS NULL

This would yield you all rows from table where their parent doesn't exist.

Sorgu yürütme ve herhangi bir sonuç silme ve yineleme bir çift sonra masa yetim özgür olmalıdır tutan bir PHP komut dosyası ile Çifti bu (bütün bu şey muhtemelen sadece bir süre döngü içinde yürütebilir bir delete deyimi içine birleştirilmiş olabilir) .

Sen çünkü geçişlilik seçme-silmek birden çok kez çalıştırmak gerekiyor - bir yetim başka bir kayda ebeveyn bir durum düşünün; ilk yineleme ile zincirdeki bir sonraki kayıt yetim yaparak, ilk yetimi kaldırmak istiyorum.

Ayrıca, (başı olduğu gibi, tanımı gereği, bir yetim), aksi takdirde boş bir tablo ile bitireceğiz, size açıkça hiyerarşinin başını atlamak emin olun.

Eğer InnoDB kullanıyorsanız, size Foreign Key Constraints Eğer yabancı anahtar ilişkileri kurarken ON DELETE CASCADE seçeneğini kullanarak sizin için bu özen içine bakmak gerekir.

Docs bir örnek:

CREATE TABLE parent (id INT NOT NULL,
                     PRIMARY KEY (id)) ENGINE=INNODB;

CREATE TABLE child (id INT, parent_id INT,
                    INDEX par_ind (parent_id),
                    FOREIGN KEY (parent_id) REFERENCES parent(id)
                    ON DELETE CASCADE) ENGINE=INNODB;

Bunun üzerine yerde, böyle bir üst ve bir alt satır eşleşen eklemek yapmak için sanki:

INSERT INTO parent (id) VALUES (1);
INSERT INTO child (id, parent_id) VALUES (1,1);

Ve sonra bu gibi ebeveyn kaldırıldı:

DELETE FROM parent WHERE id = 1;

Sen eşleşen alt kayıt gitmiş bulacaksınız. Bu, benim görüşüme göre, bunu yapmak için en iyi yoldur.

EDIT: 1 tablo içinde Bunu yapmak için, böyle bir şey yapardı:

CREATE TABLE parent (
    id INT NOT NULL,
    name varchar(250) not null,
    parent_id INT NULL,
    FOREIGN KEY (parent_id) REFERENCES parent(id) ON DELETE CASCADE,
    PRIMARY KEY (id)
) ENGINE=INNODB

Sonra iki satır, diğer başvuran birini eklerseniz:

INSERT INTO parent (id,name,parent_id)
VALUES ('1', 'Test 1', NULL), ('2', 'Test 2', '1')

Sonra iki ana satırı silin:

DELETE FROM parent WHERE id = 1;

Bunu parent_id 1 ile alt satır siler bulacaksınız.

Veri (düğüm başına yalnızca bir ebeveyn ilişkisi), ve yüksek okuma, düşük-yazma doğrusal hiyerarşik ise, bir Modifiye Preorder Ağacı Geçişi yapısı için göç düşünebilirsiniz. Bu korkutucu geliyor, ama aslında çok düzgün. Bunun üzerine büyük bir makale var burada: http://www.sitepoint.com/article/hierarchical-data-database/1/

Son derece verimli bir yapının veri alma (tek SELECT ve tüm çocukları almak) değil sadece, siz de tek bir DELETE açıklamada ağacın bütün bir dalı silmek mümkün olacak.

SAĞ KATILDI genellikle diğer veritabanları yetim bulmak için kullanılır. Ama bu bir SOL JOIN ile de mümkündür.

MySQL yetim satırları alma hakkında Here is çok güzel ortaya koydu makale

Başka bir seçenek (eğer InnoDB, 1 Paolo kullanmıyorsanız) ana MySQL masaya Delete Triggers kullanmaktır.

Bir silme tetikleyicisi kullanırken, silme satır OLD tarafından başvurulan, unutmayın. İşte bir örnek tetikleyicisi.

DELIMITER //

CREATE TRIGGER delete_clean BEFORE DELETE ON Parent
FOR EACH ROW
BEGIN
  DELETE * FROM Parent WHERE Parent.parent_id = OLD.id;
END //

DELIMITER ;