Question

Setup

(schema simplified for clarity)

Suppose I have a table called resource:

+---------------+--------------+------+-----+
| Field         | Type         | Null | Key |
+---------------+--------------+------+-----+
| id            | int(11)      | NO   | PRI |
| name          | varchar(255) | NO   |     |
| owner_id      | int(11)      | NO   |     |
+---------------+--------------+------+-----+

Each resource record is "owned" by a user defined in the user table:

+---------------+--------------+------+-----+
| Field         | Type         | Null | Key |
+---------------+--------------+------+-----+
| id            | int(11)      | NO   | PRI |
| name          | varchar(255) | NO   |     |
+---------------+--------------+------+-----+

A resources ownership can be transferred to other users by two different methods:

  1. a resource owner can request that another user takes ownership of the resource, and ownership is transferred as soon as that user accepts ownership.
  2. A user can request ownership from the current owner of a resource, ownership is transferred as soon as the current owner accepts the request.

In both cases if the request is denied by the approver, than nothing is done.

My naive implementation of the tables required to implement these concepts.

transferOwnershipRequest
+------------------------+--------------+------+-----+
| Field                  | Type         | Null | Key |
+------------------------+--------------+------+-----+
| id                     | int(11)      | NO   | PRI |
| resource_id            | int(11)      | NO   |     |
| requested_by_owner_id  | int(11)      | NO   |     |
| approver_owner_id      | int(11)      | NO   |     |
| requested_new_owner_id | int(11)      | NO   |     |
| status_id              | int(11)      | NO   |     |
+------------------------+--------------+------+-----+

transferOwnershipRequestStatus
+---------------+--------------+------+-----+
| Field         | Type         | Null | Key |
+---------------+--------------+------+-----+
| id            | int(11)      | NO   | PRI |
| status        | varchar(10)  | NO   |     |
+---------------+--------------+------+-----+

// status example data
+----+----------+
| id | status   |
+----+----------+
| 1  | pending  |
| 2  | approved |
| 3  | denied   |
+----+----------+

My business logic would update the transferOwnershipRequest.status_id as a request makes its way through the approval process.

Problem

I immediately see multiple issues with this implementation.

  • There is no way to track ownership changes over time.
  • Any timestamp fields in transferOwnershipRequest (like last_updated, request_time, approver_response_time etc) feel cumbersome
  • Any kind of fallback functionality (like reverting to a previous owner if the current owner is hit by a bus) would be difficult to implement.

Question

What are my options as far as relational database design patterns for this type of situation? Have you implemented something similar to this?

Was it helpful?

Solution

Your request table looks fine, keep it as it is, just add a general concept of "keeping track of historical records" to your other tables, this will solve all your three additional requirements.

Start by implementing the concept of ownership in a separate table "ownership":

+---------------+--------------+------+-----+
| Field         | Type         | Null | Key |
+---------------+--------------+------+-----+
| id            | int(11)      | NO   | PRI |
| resource_id   | int(11)      | NO   |     |
| owner_id      | int(11)      | NO   |     |
+---------------+--------------+------+-----+

(and remove the owner_id from resource).

Now, extend this model by adding a "history functionality" to the ownership table. There are basically two standard ways to accomplish this: either you add a nullable timestamp field to this table and use the convention "timestamp=null" means "currently valid", "timestamp set" means "ownership in the past". Or, you create a shadow table "ownership_archive", with exactly the same attributes as the "ownership" table plus the timestamp field. Then you can move old ownership records which are not valid any more after approval of a request to that table.

If necessary, you can implement similar "history functionality" for your "resource" table and your "users" table, but that will be only necessary if you need to track the history of resources and users in detail as well.

You can find a broader discussion about storing historical data in a database in this older stackoverflow question.

OTHER TIPS

Why not capture events directly, ala Event Sourcing? So, you'd have an Events table that would operate like an append only log file; rows would be immutable once written. Events have a time value so they can be ordered, and event name (request,approval,denial,etc..). (You'd probably end up putting all the event types into one table using fat table.) Ownership is considered transferred when approval event is logged. If you need to, you can have a separate owner status, reflecting the current ownership without history. (FYI, I've done some of this but not in SQL, though should work there, too.)

It looks fine to me. Add those timestamps to the request table and you have a permanent history - assuming all resources come into existence with a corresponding entry in the request table. So if you want a full history, just search that table for the resource id, and that will show you the history of ownership going back to the resource creation which would be the first entry.

You might be able to cut down the number of columns in the request table by having a request type column and then a single id for the pending new owner. Since the resource id is already connected to the current owner there's no need to specify it.

Licensed under: CC-BY-SA with attribution
scroll top