What is the database concept equivalent to "when deleting the user, delete all his posts"? - sql

What is the database concept equivalent to "when deleting the user, delete all his posts"?
And is this a good thing?
Another example: if your website is a programming forum, you need to find and delete comments related to that topic before deleting the topic.
Should this be handled automatically in the database layer?

cascading deletes
I would hesitate to recommend real deletion - instead using a soft deletion which marks a record as deleted - in this case, you might use cascading updates (or not, since the original topic has already been marked as deleted).

Cascading updates, usually used in conjunction with foreign key references. Different DBMS offer varying levels of support.
In the specific case of a forum or similar web site, I'd suggest using "soft" deletion - flag the rows in the databases as being deleted, which will prevent them from being viewed or returned in lists or search results, but don't remove them completely. This facilitates undeletion, etc. to counter shoddy or biased moderation.
In addition, I'd suggest that automatically deleting a user's posts when you delete their user account may not be the best behaviour in all cases - certainly, when dealing with troll/spam accounts, you may want to remove junk posts, but you don't necessarily want to blast away all the information in other cases, particularly as it introduces issues with broken references (e.g. external references, cross-linking from other posts, etc.)

The answer to your question is cascading deletes. For the record, I hate user deletion as a forum feature. If people want to leave, great ... I want to see the history of what they did while they were there.

Not sure if this is what you wanted to find out, but in MySQL the type of thing (I think) you're asking about is called a trigger. It's basically an SQL statement that you associate with a table and an action on that table; for example, you can set a statement that will execute whenever a user's record is deleted which will delete all comments/posts/whatever associated with that user.
see http://dev.mysql.com/doc/refman/5.0/en/create-trigger.html and links therein (that's for MySQL, of course... other DBs may differ)

Related

Is there a way to create an virtual table that would be compared to one after editing?

I have a table [contractor c] in which only one field [tin] may be edited. If the user tries to change data in other field it shall not be updated. Was wondering if making a view of the c before editing and then comparing the view with edited table is a good idea. But that would require two scripts- before and after update.
I could also make a validation on every single field except tin, but there is 'a lot' of fields.
Looking for the best and most optimal way to approach this task.
This is too long for a comment. There are many ways to do what you describe. "Views" are not one of them. In SQL, a view is a stored query. It does not store values. That is definitely not going to help, because the view changes with the underlying tables.
If only one column can be updated, then one method is to implement a trigger that checks the before- and after- versions of the record and only allows updates when no other fields change.
You can start learning about triggers in the documentation.
An alternative mechanism is to make the table unupdatable except for update permissions on a single column. You can learn about permissions in the documentation.
If for some reason you wanted to do all the work in the application, then transactions might come into use. You would not commit the transaction until the update meets your requirement. Transactions are explained in the documentation.

Effectively make database records read-only

How can I make sure that specific data in the database isn't altered anymore.
We are working with TSQL. Inside the database we store contract revisions. These have a status: draft / active. When the status has become active, the revision may never be altered anymore. A revision can have 8 active modules (each with its own table), each with their own settings and sub-tables. This creates a whole tree of tables with records that may never change anymore when the contract revision has been set to active.
Ideally I would simply mark those records as read-only. But such thing does not exists as of today. The next thing that comes to mind are triggers. Thus I have to add those triggers to a lot of tables, all which are related to the contract revision.
Now maybe there are other approaches, like a database only for archiving on which the user only has insert rights. Thus when a contract revision has become active, it is moved from one DB to the archive DB (insert is allowed). And can never be altered anymore (DENY UPDATE|DELETE).
But maybe there are other more ingenious options I haven't thought of, and you did. Maybe including the CLR or what not.
So how can I make a tree-structure of records inside our TSQL database effectively readonly that is the most maintenance free, easy to understand, quickly to setup, and can be applied in a most generic way?
What ever you do (triggers, granted rights...) might be overcome by a user with higher rights, this you know for sure...
Is this just to archive this data?
One idea coming into my mind was to create a nested XML with all data within on big structure and put this somewhere into a side table. Create a INSTEAD OF UPDATE,DELETE TRIGGER where you just do nothing. Let these tables be 1:1-related.
You can still work with this data, but not quite as fast as being read from physical tables.
If you want, you even might convert the XML to a string and calculate some Hash-Code, which you store in a different place to check for manipulations.
The whole process might be done in one single Stored Procedure call.

GetOrCreate in RavenDB, or a better alternative?

I have just started using RavenDB on a personal project and so far inserting, updating and querying have all been very easy to implement. However, I have come across a situation where I need a GetOrCreate method and I'm wondering what the best way to achieve this is.
Specifically I am integrating with OpenID and once authentication has taken place the user is redirected to my site. At this point I'd either like to retrieve their user record from Raven (by querying on the ClaimsIdentifier property) or create a new record. The user's ID is currently being set by Raven.
Obviously I can write this in two statements but without some sort of transaction around the select and the create I could potentially end up with two user records in the database with the same claims identifier.
Is there anyway to achieve this kind of functionality? Possibly even more importantly is do you think I'm going down the wrong path. I'm assuming even if I could create a transaction it would make scaling out to multiple servers difficult and in anycase could add a performance bottle-neck.
Would a better approach be to have the Query and Create operations as separate statements and check for duplicates when the user is retrieved and merge at that point. Or do something similar but on a scheduled task?
I can't help but feel I'm missing something obvious here so any advice on this problem would be greatly appreciated.
Note: while scaling out to multiple servers may seem unnessecary for a personal project, I'm using it as an evaluation of Raven before using it in work.
Dan, although RavenDB has support for transactions, I wouldn't go that way in your case. Instead, you could just use the users ClaimsIdentifier as the user documents id, because they are granted to be unique.
Alternatively, you can also stay with user ids being generated by Raven (HiLo btw) and use the new UniqueConstraintsBundle, which lets you attribute certain properties to be unique. Internally it will create an additional document that has the value of your unique property as its id.

Combining SQL Insert and Delete

Ok here is the question
I have three tables
events
- id
- name
questions
- id
- event_id
- name
answers
- id
- question_id
- description
While generating the add form, i can simply search for all the questions belonging to particular event, and show the questions in single HTML form.
But consider the edit scenario. An event manager can in due time add or delete some questions from an event. So in such case, when the user tries to edit already posted answer, I generate the HTML form with the new questions as blank field and existing answers are prefilled input boxes. How can I handle the submission of this form?
When the user submits, should i delete all past answers and do a INSERT on the answers table for all the answer values? or is it a good practice to UPDATE existing answers first and INSERT only new values?
The former obiviously being easier with DELETE followed by INSERT. While the later is somewhat tedious. The problem with former solution is that the id of the answers table will increase every time..
Some people favour the delete/insert approach because, like you say, it is simpler.
Personally I think the update/insert/delete approach, while more work, is more correct.
If you do updates you can then have an audit trail of changes to a particular item. With just insert/delete it's either much harder or plain impossible to have that kind of linkage and history.
As for how to handle the submission of the form, for fields that can be updated (ie they're existing records), you need to be able to identify the field somehow. Personally I just encode something like the primary key in the field name.
If you do this you must of course ensure that you don't have a security hole by validating that the ID supplied is valid and the edit allowed ie never trust the client.
This could take the form of:
<input type="text" name="name_117" value="Some value">
<input type="text" name="name_118" value="Some other value">
<input type="text" name="name_1243" value="Yet another value">
and you have to process all the input parameters, decode the identifier and act accordingly.
Lastly, another problem with insert/delete is that you can't do it (or it just gets really hard) if the items you're deleting/inserting relate to other tables in the database. If you have a question table and store the answers people give, normally you'll reference the question as a foreign key. You lose that association if you delete/insert instead of updating.
First, the ID shouldn't be being used for anything anyway, so disregarding the incrementation is a good reminder.
I would prefer to deal with the primary question, however, cnnceptually, everything else being equal. Is the user in fact establishing a different set of questions with their edits? Then save them as a new set. Or is the original set intended to retain its conceptual identity? Then update/delete/insert. Which seems to be more the case.
In terms of securing the integrity of the question/answer set, I think of sessions having that responsibility. You should consider validating the question set against that associated with the session.
Online quiz applications usually lock down a quiz once it is live. It is a messy problem to deal with completed answer sets versus a changing definition of questions. If your application can handle it, I would favor not allowing questions to change once an event is first published.
Agree with Cletus post, writing seperately for an extra reason and an idea:
The delete/insert approach has a concurrency issue, when your website gets some heavy traffic. Someone else could do an insert after your delete, and then you'll end up with multiple answer lists per user.
MySQL supports the ON DUPLICATE KEY UPDATE syntax. That might be an easy way to combine the insert and the update, if you have an appropriate primary key.

override constraint from no action to cascading at runtime

I feel like I have a very basic/stupid question, yet I never saw/read/heard anything in this direction.
Say I have a table users(userId, name) and a table preferences(id, userId, language). The example is trivial but could be extended to a situation with multi-level relations and way more tables..
When my UI requests to delete a user I first want to show a warning stating that also its preferences will be deleted. If at some point the database gets extended with more tables and relationships, but the software isn't adapted accordingly (the client didn't update) a generic message should be shown.
How can I implement this? The UI cannot know about the whole data structure and should not be bothered to walk down all the relations to manually delete all the depending records.
I would think this would be with constraints.
The constraint would be no action at first so the constraint will throw an error that can be caught by the UI. After the UI receives a confirmation, the constraint should become a cascade.
Somehow I'm feeling like I'm getting this all wrong..
What I would do is this:
The constraint is CASCADE
The application checks if preferences exist.
If they do, show the warning.
If no preferences exist, or the warning is accepted, delete the client.
Changing database relationships on the fly is not going to be a good idea!!
Cheers,
RB.
If you are worried about the user not realising the full impact of their delete, you might want to consider not actually deleting the data - instead you could simply set a flag on a column called say "marked_for_deletion". (the entries could then be deleted a safe time later)
The downside is that you need to remember to filter out the marked rows in other queries. This can be mitigated by creating a view on the table with the marked rows filtered out, and then always using the view in your queries.