2011-09-26 89 views
3

我目前正在開發一個學校的數據庫系統,該系統將與我們的預訂系統一起工作,以便學生可以預訂他們的課程,並且我們可以更好地跟蹤他們的活動。現在我面臨一個複雜的問題,我想要做的是檢查哪些學生合同是有效的,我可以通過使用下面的函數來實現,但我想看看是否有更簡單的方法來正確執行它(除此之外存儲我可以在系統中計算的數據。)複雜的SQL語句的可行性

如果合同有效,那麼學生沒有用完他們購買的所有小時數,購買的小時數是他們參加的教學班長度加上他們錯過但預定了每班的長度總和(在某個數字之後,例如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 

我意識到這可能是複雜的問題要問,但我只是想知道,如果這真的是做事的正確方法,或者我應該節省一些排序字段中有合約表幾個小時出席並假定它總是準確的。

+0

對一些表格定義會很好 - 我覺得我們在這裏重新建模? – Mike

+0

如果爲表格添加測試數據,並且參數的預期輸出更容易重寫。 –

+0

我可以提供一些定義,但我想知道這是否是解決問題的好方法。在我們所有的合同到期之前,我只需要檢查結束日期。但是現在他們可以有幾種不同的口味,最重要的是幾個小時。此外,該功能正在運行完美,我只是覺得我可以讓事情變得更簡單。 –

回答

2

好像你可以做幾件事情,以改善這種狀況

  1. 創建一些代碼
  2. 的看法
  3. 使用上述響應來創建一個存儲過程,並將硬編碼的ID變量 WHERE class.student_id = 5 AND booking_state_id = 4

我猜這些並不總是相同的,有一個存儲過程將允許計劃被緩存爲AD HOC SQL語句。這將允許您發送各種ID以獲得您想要的結果,並返回可用於簡單轉換爲Exce和Word表格的Web應用程序的數據集以用於報告。

+0

我明白了,我不喜歡親自使用視圖,但這看起來確實是最好的答案。 –

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