Форум: "Прочее";
Текущий архив: 2008.08.17;
Скачать: [xml.tar.bz2];
ВнизКак лучше сделать Найти похожие ветки
← →
ProgRAMmer Dimonych © (2008-06-29 15:01) [0]хранение порядка отображения элементов?
Есть таблица в БД (MySQL). В ней, например, новости сайта. Есть страница, на которой отображаются все новости. Пока всё просто.
Теперь ставим перед собой задачу: разрешить администратору сайта менять порядок следования новостей. Причём менять абсолютно независимо от каких-либо параметров новостей вродже даты создания//изменения и т.д., другими словами, нужно предоставить возможность поменять местами любую новость с любой, причём неограниченное количество раз.
Мои варианты (ни один мне не нравится :().1. Ввести в таблицу дополнительное числовое поле, при выборке упорядочивать по значению этого поля. Для обмена новостей - обновлять значение этого поля.
Пусть есть три новости, у которых значения этого order-поля равны, скажем, 35, 36 и 37. Я хочу поставить 35-ую новость между 36-й и 37-й. Если не туплю, то придётся тупо обменивать значения order-поля (в дроби уходить не хочется, они тоже имеют предел прочности). Получается 3 запроса: 1) найти две записи, между которыми будем обменивать значения order-полей; 2) обновить первую запись; 3) обновить вторую запись.2. Если уж обменивать, то почему бы не обойтись без order-поля? Брать и просто обменивать содержимое записей.
Мне кажется, очень криво получится, а если придётся добавлять к таблице новые поля, то вероятность ошибки возрастает с бешеной скоростью. Плюс, опять же, три запроса, что, как по мне, многовато.
=====
Собственно, вопрос. Как лучше сделать такую возможность?
← →
тимохов (2008-06-29 15:18) [1]давай кажддой новости значение через 1000 (т.е. 0, 1000, 2000, 3000 и т.д.). Или через сотню.
тогда обмен будет тривиален: не нужно ничего двигать - нужно будет менять числовое поле только у одной новости.
хотя если админ фанат и будет менять по 10000 тыс раз, тогда не знаю...
Имхо для решения задачи хватит с головой.
← →
Пробегал2.... (2008-06-29 15:20) [2]абсолютно непонятно - зачем.
Сложности реализации данной логики связаны именно с тем, что неправильная логика вывода информации.
Какой смысл указывать какая публикация будет идти после какой? Это в конце концов приведет к трудностям восприятия. Ведь как человек интуитивно читает список новостей?
Он ищет глазами прочтенную новость, после чего считает, что все что ниже - он уже прочел и читает только новое. Все это основывается на том, что новости идут подряд, причем в большинстве случаев - именно по дате создания или обновления новости.
Зачем ломать эту очевидную иерархию - непонятно совершенно.
Если нужно видеть сначала самые просматриваемые новости - так надо сделать кнопку фильтр типа "Показывать в порядке популярности". Если нужно самые комментируемые - аналогично.
Иногда нужно прибить объявления - то есть, новость, которая будет висеть выше остальных, какое-то системное объявление и типа того, ну это так и называется "Прилепить" или там "Важное". Реализуется легко, надо ввести только поле типа "Level", и выводятся новости по двойной фильтрации, сначала по уровню, потом по дате создания например.
В общем, описанная проблема есть продолжение неправильной логики.
← →
VirEx © (2008-06-29 15:27) [3]
> [2] Пробегал2.... (29.06.08 15:20)
тоже так считаю
как пример, допустим есть колонка новостей:
4. новость
3. новость
2. новость
1. новость
я прочитал все четыре
через пять минут админ вклинит новость 3.1:
6. новость
5. новость
4. новость
3.1 новость
3. новость
2. новость
1. новость
а я продолжу читать 5 и 6ю новости, т.к. не замечу 3.1
← →
tesseract © (2008-06-29 15:29) [4]
> абсолютно непонятно - зачем.
Выводить популярные новости первыми например. На самом деле задача решаеться по другому - лента быстрых новостей + лента популярных новостей. Ничего сложного, просто нужно вводить "градус". Тот же гугл выводит мне новости согласно моим интересам " клик рейтинг" учитывает. Мне нравиться.
← →
VirEx © (2008-06-29 15:32) [5]для примера рейтинговых новостей: news2.ru
← →
ProgRAMmer Dimonych © (2008-06-29 15:32) [6]> Пробегал2.... (29.06.08 15:20) [2]
Ну, такая логика не только у меня :)
http://www.sitepoint.com/forums/showthread.php?t=438707
http://forums.mysql.com/read.php?10,138171,138171#msg-138171
и здесь, в принципе, тоже: http://forums.mysql.com/read.php?10,116864,116864#msg-116864
Иногда вместо создания новостей "Через год", "Через полгода", "Сегодня" бывает проще создать одну новость и раз в полгода выносить её вверх. Хотя, согласен, пример с новостями не самый удачный. Можно взять, скажем, список программ, доступных для скачивания на сайте: по каким-то причинам иногда может возникать необходимость поменять их местами на странице со списком.
Ещё более яркий пример: меню сайта. Сегодня хочу, чтобы новости были первыми в меню, завтра хочу перед ними вставить раздел "О сайте".
> тимохов (29.06.08 15:18) [1]
Ну, то, что такой вариант будет работать - это здорово. Но, по-правильному, надо будет ещё писать скрипт, который эту нумерацию будет восстанавливать. Опять же, отследить, когда дошли до упора, сложно. А предполагается, что обмены будут частыми и осуществляться будут далёкими от программирования и баз данных люди, которым нельзя объяснить, что там что-то нумеруется, а потом интервал сокращается и надо иногда делать перенумерацию: они или забудут про перенумерацию, или будут её делать по десять раз в час, или, опять же, по-правильному, придётся писать скрипт, который будет напоминать про необходимость такой "дефрагментации" о мере приближения к критическому состоянию. :(
← →
Пробегал2.... (2008-06-29 15:35) [7]tesseract © (29.06.08 15:29) [4]
Выводить популярные новости первыми например
Пробегал2.... (29.06.08 15:20) [2]
Если нужно видеть сначала самые просматриваемые новости - так надо сделать кнопку фильтр типа "Показывать в порядке популярности".
← →
tesseract © (2008-06-29 15:40) [8]
> ли нужно видеть сначала самые просматриваемые новости -
> так надо сделать кнопку фильтр типа "Показывать в порядке
> популярности".
Ой ёёёёёё, читать книжки по UI, пока такое само не отвалиться.
← →
Zeqfreed © (2008-06-29 15:41) [9]> Ещё более яркий пример: меню сайта. Сегодня хочу, чтобы
> новости были первыми в меню, завтра хочу перед ними вставить
> раздел "О сайте".
Меню это обычно дерево. Там все несколько сложнее чем три запроса.
А сабжевая задача должна решаться по методу 1, потому что незачем экономить на спичках. Плюс, стоит обратить внимание на [2].
← →
Пробегал2.... (2008-06-29 15:41) [10]ProgRAMmer Dimonych © (29.06.08 15:32) [6]
ну если так, то я бы сделал одно единственное поле - например, TOP. И при выводе идет тупо сортировка по этому TOP.
А уж администратор сайта пусть сам решает как ему что делать. TOP будет иметь тип integer и по нему будет происходить сортивка первая при выводе, а как использовать - админ думает сам. Может, какие-то свои диапазоны разрабатывать, например 0-100 для вывода верхних новостей, 150-300 для вывода списка программ... ну в общем как угодно.
Следить за неповторимостью этого TOP не надо - слишком геморно. Если две новости имеют одно значение TOP - ну значит будут отсортированы в зависимости от вторичной сортировки или от того как БД сделана, это не критично.
← →
ProgRAMmer Dimonych © (2008-06-29 15:45) [11]Всем спасибо, пошёл крутить. Может написать разработчикам мускула, чтобы обмен значений сделали одним запросом? :)
← →
Пробегал2.... (2008-06-29 15:47) [12]tesseract © (29.06.08 15:40) [8]
Ой ёёёёёё, читать книжки по UI, пока такое само не отвалиться.
ой ёёёёё понт не засчитан: http://i076.radikal.ru/0806/22/1e86510f831e.jpg
← →
tesseract © (2008-06-29 15:47) [13]
> Может написать разработчикам мускула, чтобы обмен значений
> сделали одним запросом? :)
Переходи на слоника. Мускул - недобаза.
← →
Smile (2008-06-29 15:52) [14]А я тоже считаю, что всем нужно внимательно читать Пробегал2.... (29.06.08 15:20) [2]
← →
Zeqfreed © (2008-06-29 15:55) [15]> ProgRAMmer Dimonych © (29.06.08 15:45) [11]
mysql> select * from t_test;+----+-------+------+
| id | value | pos |
+----+-------+------+
| 1 | 100 | 1 |
| 2 | 200 | 2 |
| 3 | 300 | 3 |
+----+-------+------+
3 rows in set (0.00 sec)
mysql> update t_test set pos = IF(id = 1, 3, 1) where id in (1,3);
Query OK, 2 rows affected (0.00 sec)
Rows matched: 2 Changed: 2 Warnings: 0
mysql> select * from t_test;+----+-------+------+
| id | value | pos |
+----+-------+------+
| 1 | 100 | 3 |
| 2 | 200 | 2 |
| 3 | 300 | 1 |
+----+-------+------+
← →
ProgRAMmer Dimonych © (2008-06-29 18:17) [16]> tesseract © (29.06.08 15:47) [13]
> Переходи на слоника. Мускул - недобаза.
Осталось дождаться, пока это станет понятно хостеру.
> Zeqfreed © (29.06.08 15:55) [15]
Это пример с двумя запросами? Спасибо, учтём, так даже красивее получится, чем два UPDATE"а.
=====
Ещё один вопрос: Как получить значение AUTO_INCREMENT поля для вставляемой записи?
Т.е. хочу сделать что-то типаINSERT INTO MyTable(SomeField) VALUES(ID_OF_CURRENTLY_INSERTED_RECORD())
LAST_INSERT_ID() в первый раз возвращает 0, а это не есть гуд. :(
← →
Zeqfreed © (2008-06-29 18:40) [17]> Ещё один вопрос: Как получить значение AUTO_INCREMENT поля
> для вставляемой записи?
В общем случае никак. Опять чувствуется дух мисдизайна. Зачем это понадобилось? :)
← →
ProgRAMmer Dimonych © (2008-06-29 18:43) [18]> Zeqfreed © (29.06.08 18:40) [17]
> Zeqfreed © (29.06.08 15:55) [15]mysql> select * from t_test;
+----+-------+------+
| id | value | pos |
+----+-------+------+
| 1 | 100 | 1 |
| 2 | 200 | 2 |
| 3 | 300 | 3 |
+----+-------+------+
Не привязывать же к БД гадалку, чтобы она поле pos заполняла. IMHO, есть смысл вновь добавляемым записям сразу устанавливать это поле равным id и использовать DESC-сортировку.
← →
Zeqfreed © (2008-06-29 18:47) [19]> ProgRAMmer Dimonych © (29.06.08 18:43) [18]
Что мешает сделать поле pos точно так же автоматически инкрементируемым? :)
← →
ProgRAMmer Dimonych © (2008-06-29 18:50) [20]> Zeqfreed © (29.06.08 18:47) [19]
> > ProgRAMmer Dimonych © (29.06.08 18:43) [18]
> Что мешает сделать поле pos точно так же автоматически
> инкрементируемым? :)
Э-э-э... Хм... Ну... Уже второй раз за день туплю.
Спасибо.
← →
Zeqfreed © (2008-06-29 19:22) [21]> ProgRAMmer Dimonych © (29.06.08 18:50) [20]
Хм. Оказалось, что так нельзя сделать. Видимо, придется вручную рассчитывать значение. Но в принципе при вставке обычно уже известно общее число записей в таблице. А вот в постгресе, кажется, такое можно.
← →
ProgRAMmer Dimonych © (2008-06-29 21:26) [22]> Zeqfreed © (29.06.08 19:22) [21]
Да, насчёт того, что так не получится тоже увидел. Обидно :( Получается, вручную - это два запроса.
P.S. Хотя, нет. Пока писал, понял, что можно проще. Вот так ведь должно сработать?INSERT INTO MyTable(...,OrderField,...)
VALUES(...,(SELECT MAX(OrderField) FROM MyTable),...)
Вряд ли при одновременном доступе всё пройдёт гладко, но админов не так много, чтобы одновременно ухитриться обратиться к БД. :)
← →
ProgRAMmer Dimonych © (2008-06-29 21:30) [23]> ProgRAMmer Dimonych © (29.06.08 21:26) [22]
Поправочка... :)INSERT INTO MyTable(...,OrderField,...)
VALUES(...,(SELECT MAX(OrderField) FROM MyTable)+1,...)
← →
Zeqfreed © (2008-06-29 22:18) [24]Да, с подзапросом в принципе нормальный вариант.
← →
ProgRAMmer Dimonych © (2008-06-29 22:58) [25]> Zeqfreed © (29.06.08 22:18) [24]
> Да, с подзапросом в принципе нормальный вариант.
Вот, ёлки-пионерки... :( использовать в подзапросе поле, которое будет заполняться INSERT"ом не даёт.
Как в MySQLi (PHP) получить результат запросаSELECT MAX(MyField) FROM MyTable
?
← →
ProgRAMmer Dimonych © (2008-06-29 23:00) [26]> ProgRAMmer Dimonych © (29.06.08 22:58) [25]
P.S. В смысле, как получить результат скалярного запроса?
← →
Prohodil Mimo © (2008-06-30 00:10) [27]ProgRAMmer Dimonych © (29.06.08 15:01)
Пусть есть три новости, у которых значения этого order-поля равны, скажем, 35, 36 и 37. Я хочу поставить 35-ую новость между 36-й и 37-й. Если не туплю, то придётся тупо обменивать значения order-поля (в дроби уходить не хочется, они тоже имеют предел прочности). Получается 3 запроса: 1) найти две записи, между которыми будем обменивать значения order-полей; 2) обновить первую запись; 3) обновить вторую запись.
А нельзя одним запросом?
UPDATE TABLICA SET POS = POS + 1 WHERE POS >= 35
а потом инзертить 35ю новость.
Или MySQL не поддерживает тактх запросов?
← →
ProgRAMmer Dimonych © (2008-06-30 00:13) [28]> Prohodil Mimo © (30.06.08 00:10) [27]
Запросов много. Сдвинули все, которые мешают - это раз. Потом два апдейта - всё равно три. Ну, если сдвигать начинать с 37-й, то можно в два уложиться, но хорошо ли это: почти целую таблицу можно сдвигать для первых записей.
← →
Prohodil Mimo © (2008-06-30 00:17) [29]ProgRAMmer Dimonych © (30.06.08 0:13) [28]
Потом два апдейта
в каком месте? что потом апдейтить и почему два раза?
← →
Zeqfreed © (2008-06-30 00:25) [30]> ProgRAMmer Dimonych © (29.06.08 23:00) [26]
http://ru2.php.net/manual/en/mysqli-result.fetch-field-direct.php
http://ru2.php.net/manual/en/mysqli-result.fetch-field.php
Что-нибудь из этого? :)
← →
ProgRAMmer Dimonych © (2008-06-30 00:49) [31]> Prohodil Mimo © (30.06.08 00:17) [29]
Чтобы обменять, придётся отодвинуть всё лишнее подальше, а потом сделать как минимум один апдейт. Если я опять не туплю.
> Zeqfreed © (30.06.08 00:25) [30]
Уже не знаю. {Здесь грустная и виноватая улыбка} :)
Появилась бредовая идейка... Если выдрать ассоциативный массив Fetch"ем, то, по логике, индекс будет совпадать с названием поля, так ведь? Но поскольку у меня табличка пока пуста, значение должно быть равно 0, а при попытке вывода оно просто не отображается. В общем, сейчас попробую. Последний вопрос временно снимается.
← →
Anatoly Podgoretsky © (2008-06-30 09:09) [32]> Prohodil Mimo (30.06.2008 0:10:27) [27]
Если без ручного образования дырок, то три запроса.
Если с дырками, то возможно придется сделать кучу ненужной работы, например переименовать миллионы записей, вместо нескольких.
Автор привел очень плохой пример, взял три записи подряд, а ты рассмотри какая ерунда получится, если например вставить 5 между 7 и 8
Кроме того если на номер наложено ограничение уникальности, то данный метод вообще не позволит обновить и все равно непонятно зачем вторую то запись обновлять, что бы сделать 37 равным 37. А если уникальности нет, то после первого обновления будут две 35 записи и отличить их по номеру уже не получится.
Прежде чем советовать надо знать некоторые данные, имеется ли ИД и можно ли иметь одинаковые номера. Если нельзя то алгоритм будет в три запроса. И ни в коем случае не пытаться перенумеровывать миллионы записей, поскольку следующей жалобой будет жалоба на тормоз. Для указаного второго диапазона, надо 6 и 7 уменьшить на единицу, а 5 увеличить на единицу. Два запроса и минимум записей затронуто.
Прежде чем писать запросы надо голову поправить, надо что бы она была на ТЫ с реляционной и обычной логикой.
← →
Prohodil Mimo © (2008-06-30 11:54) [33]Anatoly Podgoretsky © (30.06.08 9:09) [32]
Это смотря какая логика. А если ещё и поиск дырок реализовывать, то лучше не браться. Надо делать так, чт бы дарок не появлялось. Лучше уж периодически причёсывать все записи.
Если я правильно понял, то это дело надо для админа и он не будет лопатить по сотне новых записей в секунду, что бы заметить тормоза, страница и то дольше открывается, чем пройдёт перенумерация.
Я привёл пример для вклинивания новой записи, для сдвига существующей, надо посылать как минимум два запроса, для смены номера у каждой записи из двух, меняемых местами.
В любом случае дело за автором, т.к. нам его схема неизвестна, а потому и советы такие разрозненные.
← →
KSergey © (2008-06-30 12:51) [34]Автор пытается экономить на спичках.
Основная нагрузка на сайт - это всегда его просмотр, для базы - это запросы SELECT получаются.
Для хоть сколько-нибудь популярного сайта количество запросов должно быть на несколько порядков больше обновлений. Таким образом что 2, что 3 запроса на обновление - погоды это не сделает.
Ну разве что сайт этот только и нужен для админа, который ежеминутно только и будет новости туда-сюда тасовать, а более никто туда ходить не будет.
Страницы: 1 вся ветка
Форум: "Прочее";
Текущий архив: 2008.08.17;
Скачать: [xml.tar.bz2];
Память: 0.56 MB
Время: 0.045 c