MySQL получает строки, но для любого соответствия получают последнюю версию - PullRequest
2 голосов
/ 05 июля 2010

Я разрабатываю CMS и внедряю управление версиями, добавляя новую запись в базу данных с текущей отметкой времени.

Моя таблица настроена следующим образом:

id | page | section | timestamp | content

«Страница» - это страница, к которой осуществляется доступ, это либо путь к странице ($ page_name ниже), либо «/» (для обозначения глобальных полей).

«Раздел» - это раздел редактируемой страницы.

Я хочу иметь возможность выбрать все строки для данной страницы, но каждый раздел должен быть выбран только один раз, тот, где выбрана последняя отметка времени.

Я пытался использовать следующий код активной записи CodeIgniter:

$this->db->select('DISTINCT(section), content');
$this->db->where_in('page', array('/', $page_name));
$this->db->order_by('timestamp', 'desc');
$query = $this->db->get('cms_content');

Который производит следующий SQL:

SELECT DISTINCT(section), `content`
FROM (`cms_content`)
WHERE `page` IN ('/', 'index.html') 
AND `enabled` = 1
ORDER BY `timestamp` desc

Возвращает обе тестовые строки (строки имеют все одинаковые поля, кроме id, timestamp и content).

Есть идеи, где я иду не так?

Спасибо!

Ответы [ 3 ]

2 голосов
/ 05 июля 2010

Ваша ошибка - думать, что DISTINCT относится только к разделу - легко допустить ошибку, поскольку здесь вводят в заблуждение скобки.Фактически DISTINCT применяется ко всей строке независимо от того, есть ли у вас круглые скобки.Поэтому лучше избегать скобок, чтобы избежать путаницы.

Ваша проблема - классическая проблема «максимум на группу».Существует множество способов написания этого запроса, и это, пожалуй, один из самых популярных вопросов SQL на этом сайте, поэтому вы можете выполнить поиск переполнения стека , чтобы найти способы его решения.Один из способов начать работу - выбрать только те строки, которые содержат максимальную метку времени для этого раздела:

SELECT section, content
FROM cms_content T1
WHERE page IN ('/', 'index.html') 
AND enabled = 1
AND timestamp = (
    SELECT MAX(timestamp)
    FROM cms_content T2
    WHERE page IN ('/', 'index.html') 
    AND enabled = 1
    AND T1.section = T2.section
)

Извините, но я не знаю, как преобразовать этот код SQL в активную запись CodeIgniter.Если другой пользователь, более знакомый с Active Record, пожелает использовать его в качестве отправной точки для своего собственного ответа, он приветствуется.

1 голос
/ 05 июля 2010

DISTINCT для всех выбранных столбцов, и поскольку «содержимое» отличается, вы получите две разные строки.

Вы хотите упорядочить только по отметке времени и ограничению 1, потому что вы всегда хотите самую последнюю.1004 * Но могу ли я предложить вам сохранить перекрестную ссылку на "активную" страницу?Таким образом, вы сможете вернуться к предыдущей ревизии, не создавая новые.

Значение:

page
----
id
info
active_page_id


page_revisions
--------------
id
page_id
content
timestamp
...

То есть, у вас есть один-ко-многим между pageа также как один-к-одному между page и page_revisions, чтобы отслеживать «текущую» ревизию.При таком подходе вы можете просто присоединиться к активной ревизии.

0 голосов
/ 23 июля 2012

Это сделает работу в Codeigniter без временных таблиц:

$this->db->query( "SELECT *
    FROM cms_content AS c1
    LEFT JOIN cms_content AS c2 
        ON c1.page=c2.page 
        AND c1.section=c2.section 
        AND c1.timestamp < c2.timestamp
    WHERE c2.timestamp IS NULL AND page=?", $page );
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...