Сортируемые пользователем записи - PullRequest
4 голосов
/ 24 августа 2009

Для каждого пользователя в моем веб-приложении существуют n связанные виджеты. Каждый виджет представлен в базе данных в таблице виджетов. Пользователи могут сортировать свои виджеты, у них никогда не будет больше пары дюжин виджетов, и они часто будут сортировать виджеты.

Я не имел дело с элементами базы данных, которые имеют присущий им порядок очень часто. Какова хорошая стратегия для их заказа? Сначала я думал, что простой столбец sortIndex будет работать нормально, но потом я начал задумываться, как инициализировать это значение. Предположительно, это должно быть уникальное значение, и оно должно быть больше или меньше, чем у любого другого индекса сортировки. Однако я не хочу проверять все остальные индексы сортировки для этого пользователя каждый раз, когда я создаю новый виджет. Это кажется ненужным.

Возможно, у меня мог бы быть индекс сортировки по умолчанию с "низким приоритетом"? Но тогда как я могу различать эти? Я полагаю, я мог бы использовать флаг даты создания, но что, если пользователь захочет вставить виджет в середину всех этих виджетов с низким приоритетом?

Какой стандартный способ справиться с подобными вещами?

Ответы [ 4 ]

4 голосов
/ 24 августа 2009

Если у вас есть пользователи, сортирующие виджеты по своим личным вкусам, вы хотите создать таблицу соответствия, например:

create table widgets_sorting
(
    SortID int primary key,
    UserID int,
    WidgetID int,
    SortIndex int
)

Затем, чтобы отсортировать виджеты пользователя:

select
    w.*
from
    widgets w
    inner join widgets_sorting s on
        w.WidgetID = s.WidgetID
    inner join users u on
        s.UserID = u.UserID
order by
    s.SortIndex asc

Таким образом, все, что вам нужно сделать для новых пользователей, это добавить новые строки в таблицу widgets_sorting. Убедитесь, что вы поместили ограничение внешнего ключа и индекс в столбцы WidgetID и UserID.

Эти справочные таблицы - действительно лучший способ решить отношения «многие ко многим», которые характерны для такого рода персонализированных списков. Надеюсь, это направит вас в правильном направлении!

3 голосов
/ 24 августа 2009

Лучший способ для редактируемой пользователем сортировки - сохранить id в linked list:

user_id   widget_id  prev_widget_id
   ----        ----            ----
      1           1               0
      1           2               8
      1           3               7
      1           7               1
      1           8               3
      2           3               0
      2           2               3

Это сделает 5 виджетов для user 1 в следующем порядке: 1, 7, 3, 8, 2; и 2 виджеты для user 2 в следующем порядке: 3, 2

Вы должны создать UNIQUE индексов для (user_id, widget_id) и (user_id, prev_widget_id).

Чтобы получить виджеты в заданном порядке, вы можете сделать запрос, например, в Oracle:

SELECT  w.*
FROM    (
        SELECT  widget_id, level AS widget_order
        FROM    widget_orders
        START WITH
                user_id = :myuser
                AND prev_widget_id = 0
        CONNECT BY
                user_id = PRIOR user_id
                AND prev_widget_id = PRIOR widget_id
        ) o
JOIN    widgets w
ON      w.widget_id = o.widget_id
ORDER BY
        widget_order

Чтобы обновить порядок, вам нужно обновить не более 3 строк (даже если вы переместите весь блок виджетов).

SQL Server и PostgreSQL 8.4 реализуют эту функцию, используя рекурсивные CTE s:

WITH    
-- RECURSIVE
-- uncomment the previous line in PostgreSQL
         q AS
         (
         SELECT  widget_id, prev_widget_id, 1 AS widget_order
         FROM    widget_orders
         WHERE   user_id = @user_id
         UNION ALL
         SELECT  wo.widget_id, wo.prev_widget_id, q.widget_order + 1
         FROM    q
         JOIN    wo.widget_orders wo
         ON      wo.user_id = @user_id
                 AND wo.prev_widget_id = q.widget_id
        )
SELECT  w.*
FROM    q
JOIN    widgets w
ON      w.widget_id = q.widget_id
ORDER BY
        widget_order

См. Эту статью в моем блоге о том, как реализовать эту функцию в MySQL:

1 голос
/ 24 августа 2009

Если вы имеете в виду, что каждый пользователь назначает виджеты свой порядок сортировки, то ответ Эрика верен. Предположительно, вы должны дать пользователю способ присвоить значение сортировки. Но если число скромное, как вы говорите, то вы можете просто дать ему экран со списком всех виджетов и либо позволить ему ввести номер заказа, либо отобразить их по порядку, а также расположить кнопки вверх и вниз рядом с каждым, если вы хочешь быть модным, дай ему возможность перетаскивать.

Если порядок одинаков для всех пользователей, возникает вопрос: откуда поступает этот порядок? Если это произвольно, просто назначьте порядковый номер при создании новых виджетов.

1 голос
/ 24 августа 2009

Мне нравится использовать подход с двумя таблицами - это может немного сбивать с толку, но если вы используете ORM, такой как ActiveRecord, это легко, и если вы пишете немного умного кода, им можно управлять.

Используйте одну таблицу, чтобы связать пользователя с сортировкой, и одну таблицу, чтобы связать виджет и положение и сортировку. Таким образом, становится намного яснее, что происходит, и вы можете использовать SQL-соединение или отдельный запрос для извлечения различных данных из различных таблиц. Ваша структура должна выглядеть так:

//Standard user + widgets table, make sure they both have unique IDs
CREATE TABLE users;
CREATE TABLE widgets;

//The sorting tables
CREATE TABLE sortings (
    id INT, //autoincrement etc,
    user_id INT
)

CREATE TABLE sorting_positions (
    sorting_id INT,
    widget_id INT,
    position INT
)

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

Jamie

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...