2

ライセンスの有効期限が切れているかどうかを判断するのに役立つテーブルを設計しようとしています。テーブルを構成するためのより良い方法について提案をお願いします。

具体的にやりたいことは以下の3つです。

  • ライセンスが存在するかどうかを知りたい
  • ライセンスの有効期限が切れているかどうかを知りたい
  • ライセンスの有効期限が切れていない場合は、ライセンスを延長したい

下の表を思いつきました。ユーザーのライセンスが延長されると、そのユーザーのライセンスの最初のエントリが期限切れとしてマークされます。なんらかの問題があったとしても、まだ歴史が残っているので、この方法は良いと思いました。

----------------------------------------------------------------------------
|   user_id   |   licence   |    start    |    stop          |   expired   |
----------------------------------------------------------------------------
|     22      |    other    |   03JUL2010 |    03JUL2012     |    true     | 
|     55      |  commercial |   03JUL2012 |    03JUL2014     |    true     | <= marked as expired because it was extended.
|     55      |  commercial |   04JUL2012 |    03JUL2016     |    false    | 
----------------------------------------------------------------------------

注: 04JUL2012 は、ライセンスが延長された日を示します。

これは良いアプローチのように思えますか?何か変えることはありますか?

4

2 に答える 2

1

同じレコードを 2 回保存しています。代わりに、より良いデザインに行くことができます

表1

user-id  |  license  |  start | stop | expired | extended

テーブル2

prim_key | user_id | extended_date | extended_date_expiry

table1 の拡張列はブール値 true または false です。

extended が true の場合、ユーザーが table2 で延長した日付を検索できます。

table2 では、同じユーザーの複数の延長日を保存し、履歴も取得できます。延長される最高の日付は、その user_id の有効期限になります。

于 2012-07-04T05:18:56.937 に答える
1

ユーザーとライセンスの間には 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_idlicense_idissuedissued

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元の質問に投稿した上記のスキーマに関する補足として、主キーの一部として含める必要がなくなりました。

于 2012-07-04T05:40:29.737 に答える