复杂的SQL语句可行性

时间:2011-09-26 07:52:07

标签: sql sql-server tsql sql-server-2008

我目前正在为学校开发一个数据库系统,该系统将与我们的预订系统配合使用,以便学生可以预订课程,我们可以更好地跟踪他们的活动。现在我面临一个复杂的问题,我想要做的是检查哪些学生合同是有效的,我可以通过使用以下功能来实现,但我想看看是否有更简单的方法来正确地做到这一点(除此之外)存储我可以在系统中计算的数据。)

如果合同有效,那么学生没有用尽他们购买的所有时间,购买的小时数是他们参加的教学课程长度加上他们错过的每个课程长度总和的总和。 (经过一定数量,如3或5)。我可以使用以下查询来完成它,但我觉得必须有一个更简单的方法:

SELECT
    level.name
FROM
    (
        SELECT
            contract.level_package_id,
            contract_class_hours.hours_purchased,
            (
                SELECT
                    isnull(sum(DATEPART(hh, class.end_date - class.start_date)), 0)
                FROM
                    booking
                    JOIN class ON class.id = booking.class_id
                WHERE
                    booking.booking_state_id = 3
                    AND booking.contract_id = contract.id
            ) AS time_attended,
            (
                SELECT 
                    isnull(sum(absent_class_lengths.length), 0)
                FROM
                    (
                        SELECT
                            DATEPART(hh, class.end_date - class.start_date) AS length,
                            row_number() OVER (ORDER BY class.start_date) AS rn
                        FROM
                            booking
                            JOIN class ON class.id = booking.class_id
                        WHERE
                            student_id = 5
                            AND booking_state_id = 4
                            AND booking.contract_id = contract.id
                    ) absent_class_lengths
                WHERE 
                    rn > contract_class_hours.absences_allowed
            ) as time_absent
        FROM
            contract
            JOIN contract_class_hours ON contract_class_hours.contract_id = contract.id
    ) test
    JOIN level_package_level ON level_package_level.level_package_id = test.level_package_id
    JOIN level ON level.id = level_package_level.level_id
WHERE
    test.time_absent + test.time_attended < test.hours_purchased
    AND level.study_type_id = 2
  • booking.state_id = 3表示学生上课
  • booking.state_id = 4表示学生缺席
  • level.study_type_id = 2只是一门课程

这些表包含这些数据列(忽略level_id,它只是我需要返回的值):

CLASS
    id - int
    end_date - datetime
    start_date - datetime

BOOKING
    id - int
    class_id - int
    student_id - int
    booking_state_id - smallint

BOOKING_STATE
    id - int
    state - varchar(20) [absent, attended]

CONTRACT
    id - int
    student_id - int
    level_id - int
    hours_purchased - smallint
    absenses_allowed - smallint

STUDENT
    id - int

我意识到这可能会让问题变得复杂,但我只是想知道这是否真的是正确的做事方式,或者我是否应该在合同表中保存某种具有多个字段的字段小时数,并认为它总是准确的。

2 个答案:

答案 0 :(得分:2)

似乎你可以做一些事情来改善这种情况

  1. 使用部分代码创建视图
  2. 使用上面的响应创建存储过程,并生成硬编码的ids变量 class.student_id = 5        AND booking_state_id = 4
  3. 我猜这些并不总是一样的,并且与AD Hoc sql语句相比,拥有存储过程将允许缓存计划。这将允许您发送各种ID以获得所需的结果,并返回一个数据集,该数据集可以在简单转换为和Exce或Word表格的Web applciaiton中用于报告。

答案 1 :(得分:1)

这应该产生相同的功能并且更容易阅读:

SELECT
   level.name
FROM contract
INNER JOIN contract_class_hours ON contract_class_hours.contract_id = contract.id
INNER JOIN level_package_level ON level_package_level.level_package_id = contract.level_package_id
INNER JOIN level ON level.id = level_package_level.level_id
Outer Apply(
    SELECT isnull(sum(DATEPART(hh, class.end_date - class.start_date)), 0) AS time_attended
    FROM booking
    INNER JOIN class ON class.id = booking.class_id
    WHERE booking.booking_state_id = 3
        AND booking.contract_id = contract.id
) T1
Outer Apply(
    SELECT snull(sum(absent_class_lengths.length), 0) AS time_absent
    FROM
    (
        SELECT DATEPART(hh, class.end_date - class.start_date) AS length,
            row_number() OVER (ORDER BY class.start_date) AS rn
        FROM booking
        INNER JOIN class ON class.id = booking.class_id
        WHERE class.student_id = 5
           AND booking_state_id = 4
           AND booking.contract_id = contract.id
    ) absent_class_lengths
    WHERE 
    rn > contract_class_hours.absences_allowed
) T2
WHERE T2.time_absent + T1.time_attended < contract_class_hours.hours_purchased
   AND level.study_type_id = 2