I offer a more complete model, from an actual solution.
The 'type' is associated to the question per-se (not to its items, as stated at the fourth item from the question).
A question may be of single-line or multiple-line textual box or composed by several items. For each item may be assigned a complementary question (eg. 'Country?' - 'Other' - 'Which: ___').
HOW the question and its items will be presented to the user depends on their type.
The model has been made flexible enough to represent several structures of questions.
The 'FormQuestionType' entity has an attribute to identify the ASCX (ASP.net component) responsible of rendering questions of this type.
It's possible to make a question dependent of one or more of the previous ones (eg. 'How many children?' may be made dependent of 'Do you have any children?').
There's prevision for data validation, from 'required' constraint to regular expressions.
For every major entity has been defined the mandatory and unique attribute named 'identification', allowing queries based upon textual codes instead of numerical ids (eg. 'How many children?' question, of id '351', is also identified by 'HOW_MANY_CHILDREN').
And, for the items of a given questions, there may be defined an external source of data (eg. 'city' question has its options retrieved live from corporate 'city' table).
The actual model provide versioning, but, for clarity's sake, I present a stripped down version of it.
You could always do something like this:
Create a users
table to store all of your user info:
create table users
(
id int,
user_name varchar(50)
);
insert into users values
(1, 'John'),
(2, 'Jill'),
(3, 'Bob'),
(4, 'Sam');
You state that you might need to apply this type of tracking for multiple applications. So you can create an application
table to store the app name and any details.
create table applications
(
id int,
app_name varchar(50)
);
insert into applications values
(1, 'App 1'),
(2, 'App 2'),
(3, 'App 3');
Next create a categories
table to store the info on each of the categories that you want to track by the users. This table will include a column that will contain the application id. This table will contain a foreign key relationship to the applications
table. This allows you to have some flexibility in having the same category in multiple apps.
create table categories
(
id int,
cat_name varchar(100),
a_id int
);
insert into categories values
(1, 'Cat 1', 1),
(2, 'Cat 2', 1),
(3, 'Cat 3', 2),
(4, 'Cat 4', 3);
Finally, create the users_categories
table which will contain the stats that you want to track, including user
, category
and then the action_date
(the date the event took place).
create table users_categories
(
u_id int,
c_id int,
action_date datetime
);
insert into users_categories values
(1, 1, current_timestamp()),
(2, 3, '2012-01-15 10:15'),
(3, 4, '2012-08-24 12:48'),
(1, 2, '2012-06-08 08:50');
Then to query the data, you would use something similar to this:
select *
from users u
left join users_categories uc
on u.id = uc.u_id
left join categories c
on uc.c_id = c.id
left join applications a
on c.a_id = a.id
And the results would contain (See SQL Fiddle with Demo):
ID | USER_NAME | U_ID | C_ID | ACTION_DATE | CAT_NAME | A_ID | APP_NAME
------------------------------------------------------------------------------------------
1 | John | 1 | 1 | '2012-09-28 06:47:53' | Cat 1 | 1 | App 1
1 | John | 1 | 2 | '2012-06-08 08:50:00' | Cat 2 | 1 | App 1
2 | Jill | 2 | 3 | '2012-01-15 10:15:00' | Cat 3 | 2 | App 2
3 | Bob | 3 | 4 | '2012-08-24 12:48:00' | Cat 4 | 3 | App 3
4 | Sam | (null) | (null) | (null) | (null) | (null) | (null)
A few other suggestions, you could technically remove the a_id
from the categories
table and create a join table between categories and applications, similar to this:
create table categories_applications
(
c_id int,
a_id int
);
insert into categories_applications values
(1, 1),
(2, 3),
(3, 1),
(1, 2);
This would lead to one additional join in your queries, but the results would be the same:
select *
from users u
left join users_categories uc
on u.id = uc.u_id
left join categories c
on uc.c_id = c.id
left join categories_applications ca
on c.id = ca.c_id
left join applications a
on ca.a_id = a.id
Best Answer
Adding a surrogate
id
will not help in this case. You already have a goodPRIMARY KEY(name)
, correct?The 4 columns look good for the purposes mentioned. You probably need a composite
INDEX(group_id, name)
to facilitate finding all the related queries.What do you do about nicknames that apply to two standard names?
What do you do about someone with a non-"standard" name as their 'official' name?