mysql - 如何在mysql中构建一个用于检测过期许可证的表?

标签 mysql database database-design data-structures

我正在尝试设计一个表格来帮助我确定许可证是否已过期。我希望获得有关构建表格的更好方法的建议。

具体来说,我想做以下三件事:

  • 我想知道是否存在许可证
  • 我想知道许可证是否有 已过期
  • 如果许可证尚未过期,我想延长许可证

我想出了下表。当用户的许可证延期时,该用户许可证的第一个条目将被标记为已过期。 我认为这种方法很好,因为如果出现某种问题,我仍然可以引用历史记录。

----------------------------------------------------------------------------
|   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    | 
----------------------------------------------------------------------------

注意:2012 年 7 月 4 日显示许可证延期的日期。

这看起来是个好方法吗?有什么你想改变的吗?

最佳答案

我会有三个表,因为用户和许可证之间似乎存在 N:M(多对多关系):

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]
...

userslicenses 相当简单。它们将用户和许可证固有的信息存储为独立实体。

users_has_licenses 交叉引用表中,行在三个字段中是唯一的:user_idlicense_idissued. 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,而不是一个INSERT一个更新例如您当前设计的情况:

INSERT INTO users_has_licenses VALUES (<user_id here>, <license_id here>, NOW(), NOW() + INTERVAL 4 YEAR)

编辑:解决提问者对此答案的评论:

I have one more question in regards to renewing the licence. If the user renewed their licence 6months into their first licence, how would you include that extra time in the INSERT INTO statement you listed above? I think the last value would need to be now() +remaining time + expiry period (or something like that). Unless I've misunderstood something. I'm just not sure how to get the remaining time.

假设您选择不保留过去许可期限的历史记录,您只需对当前记录进行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 作为主键的一部分。

关于mysql - 如何在mysql中构建一个用于检测过期许可证的表?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/11322686/

相关文章:

database - 用于审查评级和可选项目的架构设计

mysql - phpMyEdit 知道记录在那里 - 它们只是不显示

java - 为什么我的嵌入式 h2 程序写入 .mv.db 文件

mysql - 设计一个包含用户之间关系的表的好方法是什么?

sql - 如何在数学上做 "GROUP BY"?

mysql - SQL 查询从一个或 3 个表中选择

mySQL多维(多用户)

mysql - 选择 mysql 中只有开始日期和结束日期的事件

mysql - 多个表和 ID 不匹配的简单查询问题

mysql - 按总和(值)sql排序