LINUXTALKS.CO

Структура SQL для хранения истории изменений а-ля wiki

 ,

L


0

1
-- таблица с комментариями содержит лишь факт наличия комментария
-- указывает, какому article_id принадлежит данный комментарий
-- ну и дата-время, автор.

-- одна строка в таблице это значит что есть один комментарий

CREATE TABLE 'comments'
(
	'article_id' INTEGER,
	'comment_id' INTEGER PRIMARY KEY,
	'is_approved' NVARCHAR(1) DEFAULT '?',
	'date' DATETIME DEFAULT CURRENT_TIMESTAMP,
	'date_gmt' DATETIME DEFAULT (datetime('now', 'localtime')),
	'author_id' INTEGER,
	'author' NVARCHAR(255),
	'author_ip' NVARCHAR(45),
	'author_useragent' NVARCHAR(255)
);

-- а вот ревизий (или версий) комментария может быть сколько угодно
-- т.е. каждое редактирование комментария создаёт новую ревизию (новую версию)

-- указывает, какому comment_id принадлежит данная ревизия (история изменения)
-- а так же она указывает на text_id -- это уже другая таблица в которой уже
-- содержится сам текст комментария.

CREATE TABLE 'revision_comments'
(
	'comment_id' INTEGER,
	'id' INTEGER PRIMARY KEY,
	'date' DATETIME DEFAULT CURRENT_TIMESTAMP,
	'date_gmt' DATETIME DEFAULT (datetime('now', 'localtime')),
	'text_id' INTEGER,
	'text_comment' NVARCHAR(255),
	'text_length' INTEGER DEFAULT 0,
	'author_id' INTEGER,
	'author' NVARCHAR(255),
	'author_ip' NVARCHAR(45),
	'author_agent' NVARCHAR(255)
);

-- а тут уже лежит текст комметариев, при каждом новом редактировании комментария
-- создаётся новая ревизия и новый текст. все тексты лежат тут.

-- текст комментария хранится в отдельной таблице
-- не все СУБД умеют правильно хранить большие типы данных TEXT, BLOB

CREATE TABLE 'text_comments'
(
	'comment_id' INTEGER,
	'text_id' INTEGER PRIMARY KEY,
	'text' TEXT,
	'text_filtered' TEXT,
	'text_flags' NVARCHAR(255)
);

-- а теперь показываем все комментарии!

SELECT * FROM blog_comments

-- присоединяем таблицу с ревизиями
-- присоединяем их два раза, первый раз первую версию комментария,
-- второй раз последнюю версию комментария (если он редактировался)

INNER JOIN revision_comments AS r_init ON (r_init.comment_id = blog_comments.comment_id AND r_init.id = (SELECT id FROM revision_comments WHERE comment_id = blog_comments.comment_id ORDER BY id ASC LIMIT 1))

-- автор комментария всегда тот, кто его написал
-- т.е. имя автора всегда берётся из первой ревизии
-- даже если комментарий был отредактирован кем-то другим

LEFT JOIN user ON user.user_id = r_init.author_id

-- присоединяем текст, текст берётся всегда из последней отредактированной версии

INNER JOIN revision_comments AS r_last ON (r_last.comment_id = blog_comments.comment_id AND r_last.id = (SELECT id FROM revision_comments WHERE comment_id = blog_comments.comment_id ORDER BY id DESC LIMIT 1))

INNER JOIN text_comments ON text_comments.text_id = r_last.text_id

-- ну всякая фигня

WHERE comment_type = "comment" AND is_approved IS NULL
ORDER BY comment_id DESC
LIMIT 1000

выборка комментариев — берётся первая ревизия, оттуда берётся автор. автор всегда тот, кто первый создал комментарий.

затем берётся последняя отредактированная версия, оттуда уже берётся текст комментария, всегда последняя актуальная версия, даже если она написана другим автором.

дискасс.

★★★★★★
Ответ на: комментарий от Harald

PostgreSQL, from the manual:

Very long values are also stored in background tables so that they do not interfere with rapid access to shorter column values.

So a large character column (such as TEXT or VARCHAR without a specified size limit) is stored away from the main table data.

From the MySQL Manual:

For a table with several columns, to reduce memory requirements for queries that do not use the BLOB column, consider splitting the BLOB column into a separate table and referencing it with a join query when needed.

и вот чтобы не подстраиваться под каждую БД я уже решил хранить отдельно,

Spoofing    
★★★★★★
Linux / Firefox