Implementing a audit trail for our application [closed] - sql-server

Closed. This question is opinion-based. It is not currently accepting answers.
Want to improve this question? Update the question so it can be answered with facts and citations by editing this post.
Closed last year.
Improve this question
I want to add an audit trail for our system so when any Add/Delete/Update operation happen i will log it, with the following info:-
the CRUD operation type. is it add, delete or update.
the record ID which have been modified.
Date and time.
Now i found two approaches to follow; either to have a single audit trail table with the following fields:-
ID .such as 123445.
CRUD_description. Such as Delete
Record_ID. Such as Qaeop12771
Date. Such as 1june2O13
Or to have two tables one for a lookup table for the CRUD operation such as
CRUD_ID. such as 3.
CRUD_Description.such as Delete.
And then the Audit trial will reference the above table:-
ID. such as 123445.
CRUD_ID (this will be a foreign key to the CRUD table) such as 3.
Record_ID. Such as Qaeop12771
Date. Such as 1june2O13
So which approach is better ??
Second question If i will follow the second approach . Then is it preferred to use the CRUD_ID inside my code for example if the oprration is delete i might have my code look like:-
Inset into audit_trail (ID, CRUD_ID, Record_ID, Date) values ( 123445, 3,12771,1june2O13) //CRUID 3 represents delete operation.
Best Regards

From the viewpoint of database design (ignoring the database features and the application architecture ) I will prefer having a table for audit trail (change history) having changes per Entity and per field by implementing a flat table called Trail_History with no foreign key to any table, columns will be:
UserCode: Application user unique identifier representing who made the change. (mandatory)
TransactionCode: Any CRUD operation will need to have a unique transaction code (like GUID) (mandatory)
ChangeDate: Transaction date. (mandatory)
EntityName: Entity (table) that is being manipulated.(mandatory)
ObjectId: Entity that is being manipulated primary key.
FieldName: Entity field name.
OldValue: Entity field old value.
NewValue: Entity field new value
OperationType: CRUD operation discriminator. (mandatory)
Having this approach Any entity (table) could be traced Reports will be readableOnly changes will be logged. Transaction code will be the key point to detect changes by a single action and second question will be answered.
Hope be helpful.

Really the two approaches are prety much the same.
The seond one will be slighty more efficient but less flexible in the sense that if you need a new audit action you need to insert a new record in the type table.
The question how much information you need to audit is more interesting. Because say three users updated the record after eachother you still do not know who changed what in your design.

Related

How can I save Pending Changes? [closed]

Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed last month.
Improve this question
I have a SQL table Infos that stores some user information, the user can update his data but needs Administrator validation first,
the primary key of Infos is the referenced a lot in some others tables
Wy question is where chould I store the pending information that need validation ?
Is it a good idea to store them as JSON in a column ?
Treat this as a data modeling question. If the user information requires validation before it can be used in the application, introduce a Infos_UpdateRequest table or somesuch, that the administrator can use, and if approved copy the values from there to Infos.
You could create an Infos_Pending table with the same schema as Infos and the primary key being also a foreign key to Infos. So, your admins could load the pending records:
approval would first update the Infos record with the Infos_Pending values and then delete the Infos_Pending record
rejection would simply remove the Infos_Pending record
I would look at adding a pending approval and is active column to your table.
It would then be easy to identify which of your rows should be displayed. You could even keep older rows around for undo/history purposes.
This would mean you'd need to make changes to the sprocs/code used at your display layer, though.
I would suggest not using json or xml unless it's a situation where you always intend to chnage the entire set of values in contains.

How to enforce a one to many relationship when existing tables cannot be altered [closed]

Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed 6 years ago.
Improve this question
For background, my situation is I have a database that is missing a lot of foreign key relationships. One in particular, let's call it Orders, which represents orders with a composite primary key of OrderID and LocationID. The other table we'll call OrderDetails which has an OrderID but no LocationID. In reality, it is impossible to have an order in two locations at once, so it was assumed that there was no need to have LocationID in the details table. I didn't design it, and I can't change that.
We also have to work under the assumption there will be no support to add location id to the details table for various reasons. We are also working with Oracle and a high volume database with many concurrent users in many locations. Finally, there will be minimal time to change any applications that use this table.
So my question is: is this solution is feasible, or is there anything else I should try?
Say I create an intersection table, for lack of a better name AllOrders or whatever with primary key OrderID. Now we link Order.OrderID to AllOrders.OrderID and link OrderDetails.OrderID to AllOrders.OrderID. Would it be reasonable then to fill in AllOrders via a trigger on each insert to Orders to enforce the integrity? I am assuming all applications are inserting details after orders or the changes to enforce would be minimal and allowed.
Are there any better solutions? I understand we would do this differently if in charge of designing or given more leeway for fixing, but I'm trying to make the most given the constraints.
Edit --
To clarify what I am looking to accomplish, I want to treat all orders with the same ID as an equivalence class modulo location and ensure that if any order is deleted it requires all orders with the same id deleted and all child order details to be deleted. With primary importance of no orphan details. This has to be done with minimal application changes if possible and no redesign of existing tables if possible.
Create a new table to handle the mapping going forward.
Table: Tb_order_orderdetails
Columns: OrderID, LocationID, OrderDetailsID

One-To-Many join table to avoid nullable columns [closed]

Closed. This question is opinion-based. It is not currently accepting answers.
Want to improve this question? Update the question so it can be answered with facts and citations by editing this post.
Closed 10 months ago.
Improve this question
I'M wondering myself whether am I the first programmer struggling with this problem, but i can't find anything in SO about this.
Point of my question, is it a good idea to make a One-To-Many join table, in order to prevent NULL references.
Let's explain, in our business requirements, we have some activities that causes a payment, i.e. sales, loans, rents, services etc. each activity can have zero or one or more payments.
When designing the DB, we have tables for each activity, Sales – Loans – Rents - Services etc, and a Payment table. The relation between the activities and the payments are one to many, each loan can have many payments, and each rent can have many payments.
But there is a problem, each payment can be a loan or a sale or any other activity, we need to relate it to its corresponding activity. I think about two options:
1) Add some Foreign keys in the Payments table for each kind of activity, LoanID - RentID - ServiceID etc. And make them Nullable, due to a loan is neither a service nor a rent.
I personally don't like this solution, it is very error prone, man can very easy forgot to add the matching FK due to it is Nullable, and then we don't know what this payment is about, we lose the Referential integrity. Although it is possible to overcome this problem by creating some constraint to ensure that there are Neither more nor less than one FK, but it is not so easy to create the right constraint and take into account all possible options, and it is hard to recreate the constraint when adding new FK columns.
Needless to say about the ugliness of such a table. Don't speak about the main issue of letting unnecessary nullable columns in a table.
2) A second solution, to create join tables in between for each kind of activity, called ActivityPayments i.e. LoanPayments etc., that holds the activity ID and the payment ID, like Many-To-Many table.
There aren’t the problems described above, each payment is related to its corresponding activity, there are no referential integrity loss, no Nullable columns.
The problem is however that it enlarges the Database, and adds another layer between the tables, and needs more work when joining in queries.
Has someone any idea?
Another option is to create a supertype table, say Activity, with all of the common attributes:
This should keep the number of tables small, and still allow you to identify the activity type for a payment. Note that this assumes that common attributes exist between the different activities. If that is not the case, the second option you listed is probably the way to go.
Look up the following tags in SO.
single-table-inheritance
class-table-inheritance
shared-primary-key
The info tab on these tags gives you a brief explanation, and the questions grouped under the tag will give you some examples.
Single table inheritance is similar you the solution you presented, and that you are unhappy with. Yes, it does involve NULLS. Generally, user errors here are prevented by the application.
Class-table-inheritance is like the solution offered by AMS. Note that SalesID and LoanID are listed as both a PK and an FK. This hints at the technique of shared primary key. With this, SalesID and LoanID are copies of a value in ActivityID. Again, it's the application layer that does the necessary work to mke sure the copies are right.
in this specific case (not necessarily applicable in similiar situations), we usualy calculate dynamically, in a view/function, each payment for what it was (in chronological order)
in other instances we had one sale table where each product can be a physical product or service or any other for-pay offer. so that limits all debit transactions to one tbale
HTA

Which is a good design for a database table that can be owned by two different resources, and therefore needs two different foreign keys? [closed]

Closed. This question is opinion-based. It is not currently accepting answers.
Want to improve this question? Update the question so it can be answered with facts and citations by editing this post.
Closed 11 months ago.
This post was edited and submitted for review 6 months ago and failed to reopen the post:
Original close reason(s) were not resolved
Improve this question
My application has notification settings for users that can belong to groups. A group administrator can define settings for the entire group, so that when any user performs an action, the administrator is notified. The administrator can also define settings for an individual user, which will override the group setting.
Right now I have a database with columns: group_id, action1, action2, action3, .... The actions are booleans that determine if the administrator is notified when that action is performed by a user in his or her group.
I could make a separate table owned by the User model instead of the Group model, but it feels inefficient to store the exact same data in an entirely separate table save changing the group_id to user_id.
Another option is to add user_id to the table I already have, and allow null values for group_id. When determining notification settings for a User, the application would first choose the setting based on User, and fallback to the setting where group_id is not null. This feels inefficient because there will be many null values in the database, but it definitely requires less work on my part.
Is there a design for this situation that is more efficient than the two I've described?
Generally, there are two strategies to handle a situation like this:
Use Exclusive FKs
Essentially, each of the possible parent tables will have its own, separate foreign key in the child table, and there is a CHECK enforcing exactly one of them is non-NULL. Since FKs are only enforced on non-NULL fields (meaning, when a FK is set to NULL there is no database-level validation), only one of the FKs will be enforced.
For example:
(relationship between user and group omitted)
CHECK (
(group_id IS NOT NULL AND user_id IS NULL)
OR (group_id IS NULL AND user_id IS NOT NULL)
)
Use Inheritance
Inherit user and group from a common supertype and then connect the setting to the supertype:
For more information on inheritance (aka. category, subclassing, subtype, generalization hierarchy etc.), take a look at "Subtype Relationships" chapter of ERwin Methods Guide. Unfortunately, modern DBMSes don't natively support inheritance - for some ideas about physically implementing it, take a look at this post.
This is a heavy-duty solution probably not justified for just two tables (groups and users), but can be quite "scalable" for many tables.
how about an Actions table instead?
It could have the columns:
Table Actions:
ActionId - Identity columns
Action - Store your action here; type would depend on your system
RefId - The Id for either the user or the group
RefTable - either User or Group
then when accessing the table you know your ID already, and you know if it's a group or user and can then get the appropriate action.
This make sense?
Update:
If its possible that you could have the same action for both user/group and want one to take priority (as you mentioned in your Q) you could also add a priority column and set it as a tinyInt - lower number = higher priority. Then when you select the actions you can order them by this priority. Then perform the first action, or each action in order.

Database design: Likes table [closed]

Closed. This question is opinion-based. It is not currently accepting answers.
Want to improve this question? Update the question so it can be answered with facts and citations by editing this post.
Closed 6 months ago.
Improve this question
I got two tables (for now):
Topic
Post (post is a comment for a topic)
I want to add the option to Like those objects.
so I thought about creating one table of Likes and using enum to indicate which object was liked (including the object's id of course).
by the way, if I choose this option, should it be an enum or another table represent all the objects:
id object_name
1 Topic
2 Post
another option is to create likes table for every object .
what is the best practice to take?
I think creating a separate table for each object is better.
I don't see what you gain if you use only one table. You can't use foreign keys properly also in one table.
I mean you can't add a column object_id to your table, because you do not know the table to which it will point to. In this case you have two add two columns, topic_id and post_id. Always one of the two will be NULL.
Just create another table for the likes:
tbl_posts_likes (likeID, userID, postID, like = 1, unlike = -1)
then you could write a subquery like:
SELECT SUM(like) as likeCount, SUM(unlike)
FROM tbl_posts_likes
GROUP BY postID
WHERE postID= posts.postID
Depending on how you are tracking 'likes', I would recommend adding another table called likes to the following effect:
likes (like_id, like_type)
From this point, you would simply COUNT() the number of 'likes' for each like_type (topic/post) as each time someone likes either a topic or a post, a record would be inserted. However, if you plan to track 'likes' by user, you would need to add another column for user.
If you wanted to track the individual posts or topics, you would set up a table for each object and create a foreign key contraint for the topic or post ID.
topic_likes (tl_id, topic_id)
post_likes (pl_id, post_id)
The design above would create an entry for each like. If you are only concerned with the total number of likes for each object, you could set up something like so:
likes (like_id, like_type, likes)
A table for likes is a overkill. When does anyone need to check who liked who's post. Very rarely. Its better to just maintain a count of likes and unlikes in the post table, and maintain a likes table only for archive and audit purpose. Basically for all regular operations use the counts, for audit needs.
This will prevent doing joins to calculate # of likes. Frankly accuracy of likes and unlikes is not that crucial. 99% accuracy is good enough. And consistency between API calls may cause a issue, that is very rare. Only on high load.
I also find doing operations like SUM on a database server is very costly. JOIN and then SUM, too painful and time consuming. Instead move the operation to the compute. On the API do the ++ or --. That will take the load off the DB for useless operations like this.

Resources