Tables design for a simple messaging system - sql

I got a simple message system where every message has one sender and always exact one receiver which is never the sender. So my design is like follow:
create table user
{
PersonID int,
Name varchar(255)
}
create table message
{
MessageID int,
FromPersonID int,
ToPersonID int,
Message varchar(160)
}
To get all messages of a given PersonID I write:
SELECT MessageID FROM message WHERE PersonID=FromPersonID OR PersonID=ToPersonID
Now I got two question:
Is this the proper (and fasted) way to design that relation.
How is this relation described in a Database Diagram?

Yup, that's pretty much the textbook way to do it.
Not sure what you mean by "how is it described in a diagram". In a diagram you would draw two boxes, one for each table. Then there would be two lines connecting User and Message, one labeled "from" and the other labeled "to". The exact shape of the boxes and appearance of the lines depends on what diagramming convention you are using.

You can normalize it according to your query.
for the query
SELECT MessageID FROM message WHERE PersonID=FromPersonID OR PersonID=ToPersonID
you can create a normalized structure
create table user
{
PersonID int,
Name varchar(255)
}
create table message_meta
{
FromPersonID int,
ToPersonID int,
}
create table message_data
{
MessageID int,
Message varchar(160)
}
and fire a query like
SELECT MessageID FROM message_meta WHERE PersonID=FromPersonID OR PersonID=ToPersonID
This will be more efficient. TC

Related

Is it possible to CREATE TABLE with a column that is a combination of other columns in the same table?

I know that the question is very long and I understand if someone doesn't have the time to read it all, but I really wish there is a way to do this.
I am writing a program that will read the database schema from the database catalog tables and automatically build a basic application with the information extracted from the system catalogs.
Many tables in the database can be just a list of items of the form
CREATE TABLE tablename (id INTEGER PRIMARY KEY, description VARCHAR NOT NULL);
so when a table has a column that references the id of tablename I just resolve the descriptions by querying it from the tablename table, and I display a list in a combo box with the available options.
There are some tables however that cannot directly have a description column, because their description would be a combination of other columns, lets take as an example the most important of those tables in my first application
CREATE TABLE bankaccount (
bankid INTEGER NOT NULL REFERENCES bank,
officeid INTEGER NOT NULL REFERENCES bankoffice,
crc INTEGER NOT NULL,
number BIGINT NOT NULL
);
this as many would know, would be the full account number for a bank account, in my country it's composed as follows
[XXXX][XXXX][XX][XXXXXXXXXX]
^ ^ ^ ^
bank id | crc account number
|
|_ bank office id
so that's the reason of the way my bankaccount table is structured as is.
Now, I would like to have the complete bank account number in a description column so I can display it in the application without giving a special treatment to this situation, since there are some other tables with similar situation, something like
CREATE TABLE bankaccount (
bankid INTEGER NOT NULL REFERENCES bank,
officeid INTEGER NOT NULL REFERENCES bankoffice,
crc INTEGER NOT NULL,
number BIGINT NOT NULL,
description VARCHAR DEFAULT bankid || '-' || officeid || '-' || crc || '-' || number
);
Which of course doesn't work since the following error is raised1
ERROR: cannot use column references in default expression
If there is any different approach that someone can suggest, please feel free to suggest it as an answer.
1 This is the error message given by PostgreSQL.
What you want is to create a view on your table. I'm more familiar with MySQL and SQLite, so excuse the differences. But basically, if you have table 'AccountInfo' you can have a view 'AccountInfoView' which is sort of like a 'stored query' but can be used like a table. You would create it with something like
CREATE VIEW AccountInfoView AS
SELECT *, CONCATENATE(bankid,officeid,crc,number) AS FullAccountNumber
FROM AccountInfo
Another approach is to have an actual FullAccountNumber column in your original table, and create a trigger that sets it any time an insert or update is performed on your table. This is usually less efficient though, as it duplicates storage and takes the performance hit when data are written instead of retrieved. Sometimes that approach can make sense, though.
What actually works, and I believe it's a very elegant solution is to use a function like this one
CREATE FUNCTION description(bankaccount) RETURNS VARCHAR AS $$
SELECT
CONCAT(bankid, '-', officeid, '-', crc, '-', number)
FROM
bankaccount this
WHERE
$1.bankid = this.bankid AND
$1.officeid = this.officeid AND
$1.crc = this.crc AND
$1.number = this.number
$$ LANGUAGE SQL STABLE;
which would then be used like this
SELECT bankaccount.description FROM bankaccount;
and hence, my goal is achieved.
Note: this solution works with PostgreSQL only AFAIK.

Database design for a template based evaluation system

We are working on a database to store some evaluations we conduct. There are a few different types of evaluations and some have changed over time. Because of this we need to keep a record of exactly what an evaluation looked like when it was undertaken.
I figured that the best way to support this would be through a template style system.
With:
A table saving all possible options;
A table mapping options to a template;
An evaluations table mapping a participant to a template on a date/time; and
A table mapping evaluator comments to an option of an evaluation.
This is a skeleton for the design:
CREATE TABLE options (
id SERIAL PRIMARY KEY,
option TEXT NOT NULL
);
CREATE TABLE templates (
id SERIAL PRIMARY KEY,
name TEXT NOT NULL
);
CREATE TABLE template_options (
template INTEGER NOT NULL REFERENCES templates( id ),
option INTEGER NOT NULL REFERENCES options( id ),
UNIQUE ( template, option )
);
CREATE TABLE participants (
id SERIAL PRIMARY KEY,
name TEXT NOT NULL
);
CREATE TABLE evaluations (
id SERIAL PRIMARY KEY,
template INTEGER NOT NULL REFERENCES templates( id ),
participant INTEGER NOT NULL REFERENCES participants( id ),
date TIMESTAMP WITH TIME ZONE NOT NULL
);
CREATE TABLE evaluation_data (
template INTEGER NOT NULL REFERENCES templates( id ),
option INTEGER NOT NULL REFERENCES options( id ),
evaluator_comments TEXT NOT NULL,
);
The design is able to capture our data but doesn't restrict the options saved in evaluation_data to the subset specified in the evaluation's template's option mapping. We could probably enforce it with a trigger (we can definitely do it with application logic [we are doing so at the moment]) but are we going down the wrong path with this design?
Can anybody think of a better way to do it?
Edit:
Added an example of a potential trigger we would need to use to ensure valid options are enforced with this design.
CREATE FUNCTION valid_option() RETURNS trigger as $valid_option$
BEGIN
IF NOT NEW.option IN ( SELECT template_options.option
FROM template_options
INNER JOIN templates
ON template_options.template = templates.id
WHERE templates.id = ( SELECT evaluations.template
FROM evaluations
WHERE evaluations.id = NEW.evaluation ) ) THEN
RAISE EXCEPTION 'This option is not mapped for this evaluations template.';
END IF;
RETURN NEW;
END
$valid_option$ LANGUAGE plpgsql;
CREATE TRIGGER valid_option BEFORE INSERT ON evaluation_data FOR EACH ROW EXECUTE PROCEDURE valid_option();
Remember that you need two sets of tables. The first set containing the assessment, questions, answer alternatives, categories(?) needed to display the assessment to the participant. The second set of tables to record data about the evaluation (ie. the participant taking the assessment): which assessment, which questions, which answer alternatives and in which order they were presented, which answer they entered (are they allowed to answer the same question multiple times?), etc.
We're using the following structure (I've removed topic scoring since you didn't ask about it):
Models for presenting an assessment:
Assessment: assessment_name, passing_status, version
Question: assessment, question_number, question_type, question_text
AnswerAlternative: question, correct?, answer_text, points
Models for recording an evaluation (participant taking an assessment):
Progress: started_timestamp, finished_timestamp, last_activity, status (includes "finished")
Result: user, assessment, progress, currently_active, score, passing_grade?
Answer: result, question, selected_answer_alternative, answer_text, score
To achieve your goal, I would augment this by writing the generated evaluation to a table and pointing to it from Reault. You could also record the selection and presentation criteria so you can re-generate the assessment programmatically (ie. if you're selecting the questions from a larger question db and re-ordering the answer alternatives before presenting them to the participant).

What should I make the type of a "marital status" field?

I have a field in my table "marital status" , the user has to choose (radiobutton) if he's (married, divorced, single, voeuf)
What should I make the type of this field?
Is there a boolean type?
marital status doesn't sound like a boolean anyway. It sounds like an enumeration. A boolean would be married (Y/N), although I think in this day and age you might want to be able to store multiple kinds of relationships in there, and you specified yourself that you need to store 'devorced' as well, so a boolean is out of the question.
So I'd recommend making a table named MaritalStatus, having an ID and a description. Store the various states in there, and make a foreign key to MaritalStatusID in your table.
Make it an INT field , Create another table in your database something like
CREATE TABLE dbo.MaritalStatus
(
M_ID INT PRIMARY KEY NOT NULL,
M_Status NVARCHAR(20)
)
GO
INSERT INTO dbo.MaritalStatus
VALUES
(1, 'Single'),(2,'Married'),(3,'Divorced'),
(4,'Widowed'),(5,'Other'),(6,'Prefer Not to say').... bla bla
Now in your Table in "Marital Status" field refer to a user Marital Status using INT values from dbo.MaritalStatus table's "M_ID".
Boolean or in SQL bit datatype is best when you have a situation where something can be TRUE or NOT TRUE, for someone's Marital Status there can be more than two possible values therefore you should create a separate table for all the possible Marital Status and use Foreign key constraint.
The boolean equivalent for T-SQL is bit.
Though, it seems like you want more than a yes/no answer. In this case use an int and then convert the int to an enum.
Edit: Dukeling removed the C# tag in an edit, so I am not sure how relevant this part is anymore /Edit
The enum:
enum MaritalStatus
{
Single,
Married,
Divorced,
...
}
The int from DB:
int maritalStatusFromDB = //value from DB
Convert int to enum:
MaritalStatus maritalStatus = (MaritalStatus)maritalStatusFromDB;
Be aware that your database may contain int values that are not defined in your enum, such as 10. You can check whether maritalStatusFromDB is a valid MaritalStatus as follows:
bool isValid = Enum.IsDefined(typeof(MaritalStatus), maritalStatusFromDB);
if( isValid == false )
{
//handle appropriately
}

Simulating Inheritance in Database

I am working on a database, using Sql Server 2012. In our data model we have a type of User, with basic login information, name, address, etc, etc. Some of these users will be Technicians, who have all the same properties as a User, but some other properties like Route, Ship To Location, etc.
My question is, in designing a database, how does one simulate this situation. I have thought of 2 options.
Have a foreign key in the Technician table to the PK of the User database to link them up. My worry with this one is how will I know if a user is a technician, I would have to run a query on the technicians table each time a user logs in.
Have a field in User table link up with the PK of the Technician database, and if this field is null, or -1 or whatever I know this user is not a technician. I dont see any immediate problems with this one, but I am no expert at database design.
Do either of these have an advantage, and if so, why? Currently I have 2 different tables with two completely different id's, and they are not linked in any way, which I am now facing problems because of.
lets say you have 3 different sub class type of Class user. you can have a column in User table to identify the subclass Type. for example UserTypeID. if possible values are too many you can create new table to store these userTypes.
UserTypeID
1=Technician
2=Mechanic
3=Accounttant
Edit1
UserTypeID will be exist in all sub class entities.
Also from the other comments I feel lot concerns about getting data out of sync w/o explicit RI constraint. Just wanted to make sure that this column value should not be coming from app code or user instead the sql API inserting record should find out the right value based on which sub class entity is getting the insert record.
For example Pr_InsertUser API insert new technician. This insert API first finds out why I the UserTypeId for technician and insert record in to class user and get userid. Then passes the userId and UserTypeId to subclass technician an call another private sql API Pr_Insert_Technician to insert more attributes.
So the point I am trying to make is as SQL does not support explicit FK from multiple tables to single table that should be taken care in SQL API.
Declare #user Table
(
userid int
,UserTypeID Tinyint
,username sysname
,userAddress sysname
)
Declare #Technician Table
(
userid int
,UserTypeID Tinyint
,attr1 sysname
,attr2 sysname
)
Declare #Mechanic Table
(
userid int
,UserTypeID Tinyint
,attr3 sysname
,attr4 sysname
)
Declare #Accounttant Table
(
userid int
,UserTypeID Tinyint
,attr2 sysname
,attr4 sysname
)
You may want to familiarize yourself with the way ORM's do it.
Even if you don't use an ORM. It will lay out some of the options.
http://nhibernate.info/doc/nh/en/#inheritance
http://ayende.com/blog/3941/nhibernate-mapping-inheritance

Importing data from one table to another under conditions

I need some help on how to proceed with this problem :
I have the following SQL Server tables :
Transitions
ID int,
VariableID int,
To_VariableID int,
To_ValueID int,
To_CommentInput bit,
To_SP varchar(255)
Processes
ID int,
VariableID int,
ValueID int,
Manual_Value varchar(255)
What applies for Transitions: Only one field among
To_VariableID, To_ValueID, To_CommentInput, To_SP
can be set at a time in each row.
In some cases I want certain data from Transitions to go to Processes.
Now, if To_ValueID has been set in a row in Transitions, its value should go to the ValueID field in the Processes table.
If not, then the field that is filled ( don't know which one, it could be To_VariableID, To_CommentInput, To_SP ) should go in the Manual_Value field.
Any help would be greatly appreciated!
Something like this, although your exact mapping may differ.
Insert Into Processes (Id, VariableID, ValueID, Manual_Value)
Select
Id,
VariableID,
To_ValueID,
Coalesce(To_VariableID, To_CommentInput, To_SP)
From
Transistions