Mysql
 sql >> Baza danych >  >> RDS >> Mysql

Wielopoziomowe odpowiedzi na komentarze:wyświetlanie i przechowywanie

Jest wiele sposobów. Oto jedno podejście, które lubię (i używam regularnie).

Baza danych

Rozważ następującą strukturę bazy danych:

CREATE TABLE comments (
  id int(11) unsigned NOT NULL auto_increment,
  parent_id int(11) unsigned default NULL,
  parent_path varchar(255) NOT NULL,

  comment_text varchar(255) NOT NULL,
  date_posted datetime NOT NULL,  

  PRIMARY KEY  (id)
);

Twoje dane będą wyglądać tak:

+-----+-------------------------------------+--------------------------+---------------+
| id  | parent_id | parent_path             | comment_text             | date_posted   |
+-----+-------------------------------------+--------------------------+---------------+
|   1 | null      | /                       | I'm first                | 1288464193    | 
|   2 | 1         | /1/                     | 1st Reply to I'm First   | 1288464463    | 
|   3 | null      | /                       | Well I'm next            | 1288464331    | 
|   4 | null      | /                       | Oh yeah, well I'm 3rd    | 1288464361    | 
|   5 | 3         | /3/                     | reply to I'm next        | 1288464566    | 
|   6 | 2         | /1/2/                   | this is a 2nd level reply| 1288464193    | 

... and so on...

Dosyć łatwo jest wybrać wszystko w użyteczny sposób:

select id, parent_path, parent_id, comment_text, date_posted
from comments 
order by parent_path, date_posted;

zamawianie według parent_path, date_posted zwykle generuje wyniki w kolejności, w jakiej będziesz ich potrzebować podczas generowania strony; ale będziesz chciał mieć pewność, że masz indeks w tabeli komentarzy, który prawidłowo to obsługuje -- w przeciwnym razie zapytanie działa, ale jest naprawdę, bardzo nieefektywne:

create index comments_hier_idx on comments (parent_path, date_posted);

Dla każdego pojedynczego komentarza łatwo jest uzyskać całe drzewo komentarzy podrzędnych. Po prostu dodaj klauzulę WHERE:

select id, parent_path, parent_id, comment_text, date_posted
from comments 
where parent_path like '/1/%'
order by parent_path, date_posted;

dodana klauzula where będzie korzystać z tego samego indeksu, który już zdefiniowaliśmy, więc dobrze jest iść.

Zauważ, że nie użyliśmy parent_id już. W rzeczywistości nie jest to absolutnie konieczne. Ale dołączam go, ponieważ pozwala nam zdefiniować tradycyjny klucz obcy, aby wymusić integralność referencyjną i wdrożyć kaskadowe usuwanie i aktualizacje, jeśli chcemy. Ograniczenia klucza obcego i reguły kaskadowe są dostępne tylko w tabelach INNODB:

ALTER TABLE comments ENGINE=InnoDB;

ALTER TABLE comments 
  ADD FOREIGN KEY ( parent_id ) REFERENCES comments 
    ON DELETE CASCADE 
    ON UPDATE CASCADE;

Zarządzanie hierarchią

Aby skorzystać z tego podejścia, oczywiście musisz upewnić się, że ustawiłeś parent_path prawidłowo po wstawieniu każdego komentarza. A jeśli przenosisz komentarze (co byłoby dziwnym przypadkiem użycia), musisz upewnić się, że ręcznie aktualizujesz każdą ścieżkę parent_path każdego komentarza, który jest podrzędny wobec przeniesionego komentarza. ... ale obie te rzeczy są dość łatwe, aby nadążyć.

Jeśli naprawdę chcesz być fantazyjny (i jeśli twoja baza danych to obsługuje), możesz napisać wyzwalacze, aby w przejrzysty sposób zarządzać ścieżką_rodzica -- zostawię to ćwiczenie dla czytelnika, ale podstawową ideą jest to, że wyzwalacze wstawiania i aktualizowania będą uruchamiane przed zatwierdzeniem nowego wstawiania. pójdą w górę drzewa (używając parent_id relacji klucza obcego) i odbuduj wartość parent_path odpowiednio.

Możliwe jest nawet złamanie parent_path do osobnej tabeli, która jest całkowicie zarządzana przez wyzwalacze w tabeli komentarzy, z kilkoma widokami lub procedurami składowanymi w celu zaimplementowania różnych potrzebnych zapytań. W ten sposób całkowicie izolujemy kod średniego poziomu od konieczności znajomości mechaniki przechowywania informacji o hierarchii lub dbania o nią.

Oczywiście żadna z tych wymyślnych rzeczy nie jest wymagana w żaden sposób — zwykle wystarczy po prostu wrzucić parent_path do tabeli i napisać kod w warstwie pośredniej, aby upewnić się, że jest prawidłowo zarządzany wraz ze wszystkimi innymi polami już musisz sobie poradzić.

Nakładanie ograniczeń

MySQL (i niektóre inne bazy danych) pozwala wybrać "strony" danych za pomocą LIMIT klauzula:

SELECT * FROM mytable LIMIT 25 OFFSET 0;

Niestety, w przypadku takich danych hierarchicznych, sama klauzula LIMIT nie przyniesie oczekiwanych rezultatów.

-- the following will NOT work as intended

select id, parent_path, parent_id, comment_text, date_posted
from comments 
order by parent_path, date_posted
LIMIT 25 OFFSET 0;

Zamiast tego musimy dokonać osobnego wyboru na poziomie, na którym chcemy narzucić limit, a następnie łączymy to z powrotem z naszym zapytaniem „poddrzewa”, aby uzyskać ostateczne pożądane wyniki.

Coś takiego:

select 
  a.*
from 
  comments a join 
  (select id, parent_path 
    from comments 
    where parent_id is null
  order by parent_path, post_date DESC 
  limit 25 offset 0) roots
  on a.parent_path like concat(roots.parent_path,roots.id,'/%') or a.id=roots.id)
order by a.parent_path , post_date DESC;

Zwróć uwagę na instrukcję limit 25 offset 0 , zakopany pośrodku wewnętrznej selekcji. Ta instrukcja pobierze najnowsze 25 komentarzy „na poziomie głównym”.

[edytuj:może się okazać, że będziesz musiał trochę pobawić się rzeczami, aby uzyskać możliwość porządkowania i/lub ograniczania rzeczy dokładnie tak, jak lubisz. może to obejmować dodawanie informacji w hierarchii, które są zakodowane w parent_path . na przykład:zamiast /{id}/{id2}/{id3}/ , możesz zdecydować się na dołączenie post_date jako części parent_path:/{id}:{post_date}/{id2}:{post_date2}/{id3}:{post_date3}/ . Ułatwiłoby to uzyskanie żądanej kolejności i hierarchii, kosztem konieczności wcześniejszego wypełnienia pola i zarządzania nim w miarę zmian danych]

mam nadzieję, że to pomoże. Powodzenia!



  1. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. importowanie pliku sql do bazy danych za pomocą wamp

  2. Problem z dodaniem klucza obcego za pomocą Alter Table z istniejącą bazą danych MYSQL - nie można go dodać! Pomoc!

  3. Czy przeniesienie danych z EBS do pamięci efemerycznych poprawi wydajność zapytań MySQL?

  4. Wstawianie obiektu Python datetime.datetime do MySQL

  5. Jak mogę wygenerować turniej okrężny w PHP i MySQL?