ユーザーとライセンスの間には N:M (多対多の関係) があるように見えるため、3 つのテーブルが必要になります。
users
------------
user_id [PK]
...
users_has_licenses
----------------------
user_id [PK] (references users.user_id)
license_id [PK] (references licenses.license_id)
issued [PK]
expire_date
licenses
-------------------
license_id [PK]
...
テーブルusers
とテーブルlicenses
はかなり単純です。これらは、ユーザーとライセンスに固有の情報をスタンドアロン エンティティとして格納します。
相互参照テーブルでは、行は、、およびusers_has_licenses
の 3 つのフィールドで一意です。ライセンスの発行日または開始日を表す日時フィールドです。ユーザーはライセンスを複数回更新でき、ライセンス更新の履歴を保持する必要があるため、複合主キーの一部としてこのフィールドを含めます。user_id
license_id
issued
issued
expired
データ自体から有効期限が切れているかどうかを既に確認できるため、フィールドがなくてもかまいません。データを最新の状態に保つために定期的な更新を行う必要はありません。たとえば、ユーザーの期限切れのライセンスを見つけるには、次のクエリを実行するだけです。
SELECT
a.license_id
FROM
(
SELECT user_id, license_id, MAX(issued) AS issued
FROM users_has_licenses
WHERE user_id = <user_id here>
GROUP BY user_id, license_id
) a
INNER JOIN
users_has_licenses b ON
a.user_id = b.user_id AND
a.license_id = b.license_id AND
a.issued = b.issued AND
b.expire_date < NOW()
予想よりも少し多忙ですが、それは過去のライセンス更新のデータを保持しているからです。その場合、最新のライセンス期間を取得していることを確認するために、グループごとの最大数を実行する必要があります。最初のサブ選択では、特定のユーザーの各ライセンスの最新のものを見つけ出し、ライセンスexpire_date
が既に渡されているという条件で参加します。
有効期限が切れているかどうかに関係なく、ユーザーのすべてのライセンス (最新の期間) を取得し、有効期限が切れているかどうかを確認したい場合は、 を に変更するだけで、有効期限が切れていないINNER JOIN
すべてLEFT JOIN
のライセンスのNULL
値が になります。結合されたテーブル。
ユーザーのライセンスを更新するには、現在の設計の場合のようにとINSERT
ではなく1 つだけ必要です。INSERT
UPDATE
INSERT INTO users_has_licenses VALUES (<user_id here>, <license_id here>, NOW(), NOW() + INTERVAL 4 YEAR)
編集:この回答に対する質問者のコメントへの対処:
免許の更新について、もう一つ質問があります。ユーザーが最初のライセンスの 6 か月後にライセンスを更新した場合、上記の INSERT INTO ステートメントにその余分な時間をどのように含めますか? 最後の値は now() +残り時間 + 有効期限 (またはそのようなもの) である必要があると思います。私が何かを誤解していない限り。残りの時間を取得する方法がわかりません。
過去のライセンス期間の履歴を保持しないことを選択したと仮定するとUPDATE
、現在のレコードに対して実行できます。
UPDATE users_has_licenses a SET
a.issued = NOW(),
a.expire_date = (
SELECT
NOW()
+ INTERVAL CASE WHEN DATEDIFF(expire_date, NOW()) < 0 THEN 0 ELSE DATEDIFF(expire_date, NOW()) END DAY
+ INTERVAL 4 YEAR
FROM
users_has_licenses
WHERE
user_id = a.user_id AND
license_id = a.license_id
)
WHERE
a.user_id = <user_id here> AND
a.license_id = <license_id here>
それはissued
現在の日付に更新され、expire_date
現在の日付+古い期間の残りの日数+通常の有効期限(それが何であれ)に更新されます。過去のライセンスがすでに期限切れになっている場合、残りの日数はマイナスになります。この場合、通常の有効期限を追加するだけです。
issued
元の質問に投稿した上記のスキーマに関する補足として、主キーの一部として含める必要がなくなりました。