MVC application - where to store reference data - model-view-controller

I am working on an application using the Yii framework, so its MVC-style. I have a record type "person", which contains information about membership. Members come in two types: adults & kids. With the kids, SOME of them we know their ages and they are divided into age groups. The age groups have names (e.g. "8 & Under".) So as an example, John Smith & Jane Smith have two kids Jimmy Smith and Janey Smith. Janey wants to do a soccer program, so we need to know her age and put her in an age group. Jimmy is doing arts & crafts so we don't need to know his age because his program isn't divided by age. And we don't ask for the ages of the adults.
So the question: I have a few choices about how I store this. I could:
put an int agegroup field in the person table, and define the values as CONST values when I define the model for people (and probably have a special value for "undefined" - for the adults. Then I need to write a little code to translate the const value to descriptive labels.
put an agegroup field in the person table as above, but also add another table in the database with the reference data. Enforce referential integrity to this new table. This raises another question - should I create a dummy record in the reference table for cases where I don't know/care about the agegroup, or should I allow null values in the people table agegroup field?
others?
I know I can make either of these work. But I would welcome advice on which approach is preferred and why!

For the possibility of future expansion (you may want to create, delete, and modify age groups) I would recommend having an age group table consisting of a beginning age, an upper limit age, and a description. You can leave the beginning age as null to signify a 'up to n'/'n and lower' group, or vice versa with the upper limit. The primary key would consist of the beginning and upper age together (composite key.)
Then, in your 'activities' table, you would need to enforce a reference to the age group table (even if just to a 'null/null' or 'all ages' record.) This way you can create activities for age groups -- 8 and under soccer, 12 to 14 soccer, all ages crafts, 18 and older art, and so on.

Related

Validate that value is unique over multiple tables access

Scenario: I have to create a database which has to contain 3 different tables holding information about people. Lets call them Members, Non_Members and Employees. Among the other information they may share , one is the telephone number. The phone numbers are unique, each in its respective table.
My problem: I want to make sure the phone number is always unique among these 3 tables. Is there a way to create a validation rule for that ? If not and I need to redesign the database, which would be the recommended way to do it.
Additional info: While the 3 tables hold the same information (Name , address etc.) its not required always required to fill them. So I am not sure if a generic table named Persons would work for my case.
Some ideas: I was wondering if and how I can use a query as a validation rule (that would make things easier). If I would end up creating a table called Phone numbers , how would the relations between the 4 tables would work in order to ensure that each of the 3 tables has a phone number.
ERD
I assume you are talking about a relational database.
I would go for a single person table with a "type" column (member, non_member, ...). That is much more flexible in the long run. It's easy to add new "person types" - what if you later want a "guest" type?
You would need to define as nullable to cater for the "not all information is required" part.
With just a single table, it's easy to make the phone number unique.
If you do need to make it unique across different tables, you need to put the phone numbers in their own table (where the number is unique) and the references that phone_number table from the other tables.
Edit
Here is an example of creating such a phone_number table:
create table phone_number
(
id integer primary key,
phone varchar(100) not null unique
);
create table member
(
id integer primary key,
name varchar(100),
... other columns
phone_number_id integer references phone_number
);
The tables non_member and employee would have the same structure (which is a strong sign that they should be a single entity)
Edit 2 (2016-01-08 20:12)
As sqlvogel correctly pointed out, putting the phone numbers into a single table doesn't prevent a phone number to be used by more than one person (I misunderstood the requirement so that no phone number should be stored more than once)

Should I store US states as an array or create table columns?

I have an app that houses product data via a Product model and table. Each product has specific state availability (multiple states) that I will need to filter and/or search by in the future. I am hoping to find someone who can tell me the most efficient way to store this data. As I see it, I have two options.
The first is to simply create 50 columns in my table, titled with each state name and containing a boolean value. I can then simply filter by = "avail in California" if product.ca. While this certainly works, it seems a bit cumbersome, especially when searching for multiple state availability.
The second option would be to simply have one column("states") that stores an array of available states and then filter by = "avail in California" if product.states.include? "CA". This seems like a better solution for two reasons. The first, it just allows for a cleaner DB table. Second, and more important, I can allow my user to search by simply saving the user's input as a variable(user_input) and then = "avail in California" if product.states.include? user_input. This solution does call for a little more work up front however when saving the product in the DB, since I won't be able to simply check off a boolean value.
I think option two makes the most sense, but am hoping for some advice as to why or why not. I have found a few similar questions, but they do not seem to explain which solution would be better, just how to accomplish each.
What should I do?
You should normalize unless you have a really good reason not to, and I don't see one in your overview.
To normalize, you should have the following tables:
product table, one record per product
state table, one record per state
product_state table, one entry for every product that is in a state
The product_state schema looks like this:
(product_state_id PK, product_id FK, state_id FK)
UNIQUE INDEX(product_id,state_id);
This allows you to have a product in zero or more states.
I assume that since you’re selling products, you will be charging taxes. There are different taxes by state, county, city. There are country taxes in some countries too.
So you need to abstract these entities into a common parent, usually called GeopoliticalArea, so that you can point a single foreign key (from, say, a tax rates table) at any subtype.
create table geopolitical_area (
id bigint primary key,
type text not null
);
create table country (
id bigint primary key references geopolitical_area(id),
name text not null unique
);
-- represents states/provinces:
create table region (
id bigint primary key references geopolitical_area(id),
name text not null,
country_id bigint references country(id),
unique (name, country_id)
);
insert into geopolitical_area values
(1, 'Country'),
(2, 'Region');
insert into country values
(1, 'United States of America');
insert into region values
(2, 'Alabama', 1);

How to save different surveys to database

I'm assigned to make a web based survey application on ASP.NET MVC3.
And I have three different surveys. I have to the way best way to store survey answers on database. I'm came up with only one solution: To make an answer table for each survey type.
Can you suggest better solutions?
You can have single table itself for Answers with Survey type as a Column.
perhaps something like this?
table survey_answers
id (this is the pk) : qid (question id): answer (varchar MAX) : pid (person id)
what you can do with this is make a questions table, a person table. in the question table, put the qid, the question, and the group of questions it belongs to (the survey id). Persons table is obvious, you put a pid (person id) and info about the person (such as name, age, gender etc.)
the reason that a three table approach is bad is because let's say the amount of surveys you have grows. let's see it becomes 100 different types of surveys or more - which is a definite possibility depending on where you work - are you going to have 100 different tables? 1000? no way.

Struggling with a data modeling problem

I am struggling with a data model (I use MySQL for the database). I am uneasy about what I have come up with. If someone could suggest a better approach, or point me to some reference matter I would appreciate it.
The data would have organizations of many types. I am trying to do a 3 level classification (Class, Category, Type). Say if I have 'Italian Restaurant', it will have the following classification
Food Services > Restaurants > Italian
However, an organization may belong to multiple groups. A restaurant may also serve Chinese and Italian. So it will fit into 2 classifications
Food Services > Restaurants > Italian
Food Services > Restaurants > Chinese
The classification reference tables would be like the following:
ORG_CLASS (RowId, ClassCode, ClassName)
1, FOOD, Food Services
ORG_CATEGORY(RowId, ClassCode, CategoryCode, CategoryName)
1, FOOD, REST, Restaurants
ORG_TYPE (RowId, ClassCode, CategoryCode, TypeCode, TypeName)
100, FOOD, REST, ITAL, Italian
101, FOOD, REST, CHIN, Chinese
102, FOOD, REST, SPAN, Spanish
103, FOOD, REST, MEXI, Mexican
104, FOOD, REST, FREN, French
105, FOOD, REST, MIDL, Middle Eastern
The actual data tables would be like the following:
I will allow an organization a max of 3 classifications. I will have 3 GroupIds each pointing to a row in ORG_TYPE. So I have my ORGANIZATION_TABLE
ORGANIZATION_TABLE (OrgGroupId1, OrgGroupId2, OrgGroupId3, OrgName, OrgAddres)
100,103,NULL,MyRestaurant1, MyAddr1
100,102,NULL,MyRestaurant2, MyAddr2
100,104,105, MyRestaurant3, MyAddr3
During data add, a dialog could let the user choose the clssa, category, type and the corresponding GroupId could be populated with the rowid from the ORG_TYPE table.
During Search, If all three classification are chosen, It will be more specific. For example, if
Food Services > Restaurants > Italian is the criteria, the where clause would be 'where OrgGroupId1 = 100'
If only 2 levels are chosen
Food Services > Restaurants
I have to do 'where OrgGroupId1 in (100,101,102,103,104,105, .....)' - There could be a hundred in that list
I will disallow class level search. That is I will force selection of a class and category
The Ids would be integers. I am trying to see performance issues and other issues.
Overall, would this work? or I need to throw this out and start from scratch.
I don't like the having three columns for the "up to three" classifications. In my opinion it would be better to have a cross-reference table that allows your many-to-many mapping between organisation and type, i.e. table ORGANISATION_GROUPS with columns OrganisationId, OrgGroupId.
To sort out the problem of being able to query a different levels of classification specified you could setup this cross-ref table to hold the actual classifications, i.e. ORGANISATION_GROUPS instead has columnns: OrganisationId, ClassCode, CategoryCode, TypeCode.
This will make queries at different levels of classification very easy.
For referential integrity to work with this scheme I'd then suggest not using surrogate integer keys for your ORG_* tables but instead setting the primary key to be the real unique key, i.e. ClassCode, CategoryCode, TypeCode for ORG_TYPE.
The problem i see in your design is that it is a bit rigid. A more flexible approach you might want to consider is following:
First you would have a table for classes, categories, types and any other classification type. This table would be auto-referenced. All registers would have a field referring to its immediate parent, like following:
CLASSIFICATION (Id, Description, Parent_Id)
ITAL, Italian, REST
CHIN, Chinese, REST
MEXI, Mexican, REST
REST, Restaurant, FOOD
Next you would have, as #John pickup suggested, an intermediate cross-reference table between your restaurant (or whatever you need) table and the classification table which would contain only a composite primary key, being its components the primary key of both tables.
FOODSERVICE_CLASSIFICATION (Rest_Id, Class_Id)
100, ITAL
100, CHIN
101, MEXI
102, CHIN
It would be advisable to limit it so that only leaf registers of the CLASSIFICATION table can be referenced in the cross-reference table.
Your example of looking for all restaurants would be as simple as looking for all child categories of REST and search for them in the cross-reference table. This can be written in a single select in Oracle (not sure about other RDBMS).
This way you can:
have multiple categorization for your restaurants without being limited to 3 categories.
Do quick searches using the cross-reference table.
Mind you, this schema would work supposing your categorization is like a tree with a base category acting as the root. If instead you need a more loose categorization you would probably need a tags approach.
Btw, I also agree with #John Pickup that it is better to use real primary keys in this case.
HTH

How do you deal with "Many Names for 1 Person"?

One of the most common problems I run into when creating any information system is the fact that people go by so many different names. Someone named "Bill Smith" may go by "Will Smith","William Smith", "Smith, Will", etc... If say, I wanted to write an application to link blog posts to authors, I would have to account for all those names.
My question is: What approaches do you take to keep consistent data throughout your application. How do you structure your database so that you can refer to a single identifier to locate all those names? What UI approaches do you take make sure that people enter in names in a consistent manner?
As long as you have a unique id for each user (which is not their name) you can have a table that maps name variations to a unique id, and then associate each post with that unique ID.
(Table mapping names to UIDs)
Name UID
Robert S 123456
Bob S 123456
Bert S 123456
Darren 987654
(Table with post information, including author's UID)
Title Author ...
Post 1 123456
Post 2 123456
Post 3 987654
(Table with author information)
UID Preferred Name Webpage ...
123456 Robert Smith http://www.robert.com
987654 Darren Jones http://www.jones.com
It's probably a good idea to accept only one name from your user, and allow them a "nickname" or a "public name". That gives them the freedom to have a legal name, perhaps for mailing or billing, and a public-viewable name for interaction on your site.
Beyond that, I don't think I would allow my users to have multiple names, unless my system required it. If I did, I'd split it up into two tables:
Users:
userid (ex: 1821)
UserNames:
userid (ex: 1821)
firstName (ex: Jonathan)
lastName (ex: Sampson)
In addition, you could add a field in the usernames table called 'isPrimary'. This would be a boolean value that will tell you which name to treat as the primary name for the user. This is similar to how wikipedia store a history of data/changes. They keep all, but mark which is "active", or in your case "primary".
It sounds to me like you are trying to use their name as a primary key or UID. This is the wrong way to go. You should have a seperate UID as the primary key, then the name can be whatever you want, and you can even have a list of alternate names.
The real problem happens when you have multiple applications, and each one has their own schema for user information. The billing system might have "Will Smith"; the payroll system might have "William Smith"; the claims system might have "Willie X. Smith". All are really the same person. What do you do? It's a huge issue for stovepipe, legacy apps.
I agree with the first 3 posts on how to structure your schema.
In regards to the UI I would allow a field for the persons legal first,middle and lastname which should change very rarely.
Then allow nickname(s) depending on your application requirements.
Having their full legal name can come in handy for billing/financial/HR situations too.
You could always make a AKA table, where you could have the prefer name to AKA name. So if someone uses the name Bill, you can always replace it with William.
I have never personally used this concept for names, but I do support a project that does something similar with Movie Titles, which can varied for different countries.

Resources