私のデータベース設計といくつかのユースケースに関する詳細なメモ。
テーブルデザイン
これは、イベントを格納するメイン テーブル (基本的に iCalendar スキーマに基づく) です。イベントは、典型的なイベント、または会議、祝日などです。
event (event_id (PK), dtstart, dtend, ... --other icalendar fields--)
特定の種類のイベントに追跡しなければならない追加情報がある場合は、別のテーブルで飾ります。たとえば、e-leave 固有の情報を格納するテーブル。(要件の一部として、total_days は計算フィールドではありません)
event_leave (event_id (PK/FK->event), total_days, leave_type_id (FK->leave_type))
休暇タイプ テーブルには、各休暇タイプに関する情報が格納されます。たとえば、アプリケーションには承認/推奨などが必要ですか。それに加えて、許可された最大繰越も保存されます。最大繰越額は頻繁に変更されることはないと思います。
leave_type (leave_type_id (PK), name, require_support, require_recommend, max_carry_forward)
ユーザーはグループに分けられ、各グループには、いくつかの leave_typeに対して休暇を取得できる日数が与えられます。このテーブルに保存されているデータは、毎年入力されます (毎年新しいリビジョン)。ユーザーごとではなく、グループごとに与えられた休暇の数のみを保存します。
leave_allocation (leave_allocation_id, year(PK), leave_type_id (PK/FK->leave_type), total_days, group_id)
次は、繰り越し情報を格納するテーブルです。このテーブルは、ユーザーごとに 1 年に 1 回作成されます。その場での計算は容易ではないため、このテーブルは年に 1 回入力されます。ユーザーの leave_carry_forward をカウントする式は次のとおりです。
leave_carry_forward(2009) = min(leave_allocation(2008) + leave_carry_forward(2007) - leave_taken(2008), maximum_carry_forward());
leave_carry_forward (leave_carry_forward_id, user_id, year, total_days)
ユースケースとソリューションの例
残高の計算 (WIP)
残高を計算するには、次のように宣言されたビューにクエリを実行します
DROP VIEW IF EXISTS leave_remaining_days;
CREATE OR REPLACE VIEW leave_remaining_days AS
SELECT year, user_id, leave_type_id, SUM(total_days) as total_days
FROM (
SELECT allocated.year, usr.uid AS "user_id", allocated.leave_type_id,
allocated.total_days
FROM users usr
JOIN app_event._leave_allocation allocated
ON allocated.group_id = usr.group_id
UNION
SELECT EXTRACT(year FROM event.dtstart) AS "year", event.user_id,
leave.leave_type_id, leave.total_days * -1 AS total_days
FROM app_event.event event
LEFT JOIN app_event.event_leave leave
ON event.event_id = leave.event_id
UNION
SELECT year, user_id, leave_type_id, total_days
FROM app_event._leave_carry_forward
) KKR
GROUP BY year, user_id, leave_type_id;
年の初めに leave_allocation テーブルにデータを入力する
public function populate_allocation($year) {
return $this->db->query(sprintf(
'INSERT INTO %s (%s)' .
"SELECT '%s' AS year, %s " .
'FROM %s ' .
'WHERE "year" = %s',
'event_allocation',
'year, leave_type_id, total_days ...', //(all the fields in the table)
empty($year) ? date('Y') : $year,
'leave_type_id, total_days, ..', //(all fields except year)
$this->__table,
empty($year) ? date('Y') - 1 : $year - 1
))
->count() > 0; // using the database query builder in Kohana PHP framework
}
年の初めに leave_carry_forward テーブルに入力します
ユーザーに割り当てられた休暇の種類を調べる
おそらく、このビューの名前を変更する必要があります (名前の付け方が下手です...)。実際には、ユーザーの leave_allocation テーブルです。
DROP VIEW IF EXISTS user_leave_type;
CREATE OR REPLACE VIEW user_leave_type AS
SELECT la.year, usr.uid AS user_id, lt.leave_type_id, lt.max_carry_forward
FROM users usr
JOIN app_event._leave_allocation la
JOIN app_event._leave_type lt
ON la.leave_type_id = lt.leave_type_id
ON usr.group_id = la.group_id
実際のクエリ
INSERT INTO leave_carry_forward (year, user_id, leave_type_id, total_days)
SELECT '{$this_year}' AS year, user_id, leave_type_id, MIN(carry_forward) AS total_days
FROM (
SELECT year, user_id, leave_type_id, total_days AS carry_forward
FROM leave_remaining_days
UNION
SELECT year, user_id, leave_type_id, max_carry_forward AS carry_forward
FROM user_leave_type
) KKR
WHERE year = {$last_year}
GROUP BY year, user_id, leave_type_id;