Сортировка и фильтрация записей - PullRequest
0 голосов
/ 17 ноября 2008

существует ли какой-либо известный шаблон / алгоритм, как правильно выполнять сортировку или фильтрацию списка записей (из базы данных)? Моя текущая попытка включает в себя использование формы, которая предоставляет некоторые параметры фильтрации и сортировки, а затем добавить эти критерии и алгоритм сортировки в мой существующий SQL. Тем не менее, я считаю, что можно легко злоупотреблять тем, что пользователи могут получать результаты, которые они не должны видеть.

Приложение, которое я создаю, является планировщиком, в котором я храню все события в таблице базы данных. Затем в зависимости от уровня пользователя / роли / привилегии будет отображаться другое подмножество данных. Поэтому мой запрос может быть таким сложным, как

SELECT  * 
FROM    app_event._event_view 
WHERE   ((class_id = (SELECT class_id FROM app_event._ical_class WHERE name = 'PUBLIC') AND class_id != (SELECT class_id FROM app_event._ical_class WHERE name = 'PRIVATE') AND class_id != (SELECT class_id FROM app_event._ical_class WHERE name = 'CONFIDENTIAL')) OR user_id = '1') 
        AND calendar_id IN (SELECT calendar_id FROM app_event.calendar WHERE is_personal = 't') 
        AND calendar_id = (SELECT calendar_id FROM app_event.calendar WHERE name = 'personal') 
        AND state_id IN (1,2,3,4,5,6) AND EXTRACT(year FROM dtstart) = '2008' 
        AND EXTRACT(month FROM dtstart) = '11'

Поскольку я больше озабочен обслуживанием правильного подмножества информации, в данный момент производительность не является серьезной проблемой (так как упомянутый sql был сгенерирован сценарием, пункт за пунктом). Я думаю о том, чтобы превратить все эти сложные операторы SQL в представления, чтобы было меньше шансов, что сгенерированный SQL неуместен.

Ответы [ 3 ]

1 голос
/ 17 ноября 2008

Во-первых, этот запрос будет выглядеть и работать лучше, если вы используете объединения:

SELECT  * 
  FROM    
    app_event._event_view EV
    INNER JOIN app_event.calendar C
        ON EV.calendar_id = C.calendar.id
    INNER JOIN app_event._ical_class IC
        ON C.class_id = EV.class_id
  WHERE   
    C.is_personal = 't'
    AND C.name = 'personal'
    AND state_id IN (1,2,3,4,5,6) 
    AND EXTRACT(year FROM dtstart) = '2008' 
    AND EXTRACT(month FROM dtstart) = '11'
    AND (
        IC.name = 'PUBLIC' -- other two are redundant
        OR user_id = '1'
        )

Это хорошее начало для снижения сложности. Затем, если вы хотите добавить дополнительные фильтры непосредственно в SQL, вы можете добавить еще операторы «И ...» в конце. Поскольку все критерии связаны с AND (ИЛИ безопасно содержится в скобках), нет никакой возможности добавить после них критерий, который каким-либо образом отменяет вышеприведенные, то есть, если вы ограничили результаты одной частью предложение, вы не можете «ограничить» его более поздним предложением, если оно связано с AND. (Конечно, если эти дополнительные пункты находятся рядом с пользовательским вводом текста, их необходимо санировать, чтобы предотвратить атаки с использованием SQL-инъекций.)

База данных может фильтровать быстрее, чем любой другой уровень, в общем, потому что использование предложения WHERE для базы данных часто позволяет базе данных избегать даже чтения ненужных записей с диска, что на несколько порядков медленнее, чем все, что вы можно сделать с процессором. Сортировка часто выполняется также быстрее в БД, потому что БД часто может выполнять объединения таким образом, что записи уже отсортированы в том порядке, в котором вы их хотите. Таким образом, с точки зрения производительности, если вы можете сделать это на БД, тем лучше.

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

0 голосов
/ 17 ноября 2008

Используйте инструмент ORM или используйте такие параметры, как:

SELECT  * 
FROM    app_event._event_view 
WHERE
    (
        :p_start_year is null or
        (state_id IN (1,2,3,4,5,6) AND EXTRACT(year FROM dtstart) = :p_start_year)
    )
    and
    (
        :p_date_start is null or
        AND EXTRACT(month FROM dtstart) = :p_date_start
    )
0 голосов
/ 17 ноября 2008

Трудно понять этот запрос, потому что мне приходится многократно прокручивать, а базу данных я не знаю ...

Но если привилегии являются "одномерными", например, администраторы могут видеть все, опытные пользователи могут видеть меньше, чем администраторы, гости могут видеть меньше, чем опытные пользователи и т. д .: вы, вероятно, могли бы реализовать привилегии как целое число как в событии, так и для пользователя, тогда

select from event where conditions AND event.privilegue <= user.privilegue

Если вы установите значения привилегий, такие как 10 000 (высокая / администратор), 5000, 1 (самая низкая / гость), вы сможете позже добавить больше уровней без изменения всего кода.

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