排序和过滤记录

时间:2008-11-17 08:29:05

标签: sql filter sorting

是否有任何关于如何以正确方式对记录列表(来自数据库)进行排序或过滤的已知模式/算法?我当前的尝试涉及使用提供一些过滤和排序选项的表单,然后将这些标准和排序算法附加到我现有的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是由脚本生成的,by clause子句)。我正在考虑将所有这些复杂的SQL语句转换为视图,因此SQL生成的机会不太合适。

3 个答案:

答案 0 :(得分:1)

首先,如果您使用连接,此查询将会更好看并执行:

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相关(OR被安全地包含在括号内),因此不可能有人在这些之后添加一个标准,以某种方式解除上面的标准 - 也就是说,一旦你用一个部分限制了结果如果它与ANDs串在一起,你不能用后面的句子“解除限制”它。 (当然,如果这些附加条款接近用户文本输入,则必须对它们进行清理以防止SQL注入攻击。)

一般情况下,数据库可以比任何其他层过滤得更快,因为在数据库上使用WHERE子句通常会让数据库甚至无法从磁盘上读取不必要的记录,这比你的任何东西慢几个数量级可以用CPU做。数据库上的排序通常也更快,因为数据库通常可以以记录已按您希望的顺序排序的方式进行连接。所以,性能方面,如果你能在数据库上做到这一点,那就更好了。

你说性能并不是真正关键的,所以在业务逻辑中以编程方式添加过滤器对你来说可能没问题,而且比乱用SQL字符串更容易阅读。

答案 1 :(得分:0)

很难理解这个查询,因为我必须大量滚动,因为我不知道数据库......

但如果特权是“一维的”,例如管理员可以看到所有内容,高级用户可以看到少于管理员,客户可以看到少于高级用户等等。您可以在事件和用户中将权限实现为整数,然后

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

如果您将特权值设置为10 000(高/管理员),5000,1(最低/客人),您可以稍后在不更改所有代码的情况下在其间添加更多级别。

答案 2 :(得分:0)

使用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
    )