the same field in multiple tables - mysql

I have the following tables: trainers, trainees and health professionals.
I need to incorporate the mailing list field into each of them to flag those people who want to receive our newsletter.
Is it ok to have the same filed in each of these tables, or there is a better way to resolve this issue?
Many thanks, Zan

You should probably have one single people table, which contains mailing_list. Then if you have different data that needs to be stored for trainers, trainees etc, hold this in separate tables and make them joinable through the use of a foreign key.

I would try to avoid duplicate the data as much as possible,
for the mailing list, here how I would do to avoid having to repeat it in different tables with
Foreign keys
| trainers | | trainees | | Health_prof |
|_________________| |_________________| |_________________|
| .... | | .... | | .... |
| mailing_list_id | | mailing_list_id | | mailing_list_id |
and a table mailing list
| mailing_list |
|_________________|
| mailing_list_id |
| all orther infos|
in the case your persons can be registered to multiple mailing list I would use a third table to make the link between the people and the mailing list with the corresponding ID's as rows, so to register, unregister you would just have to insert/delete rows in this table

Assuming that there is common information (such a name, gender, date of birth, email address, etc) for trainers, trainees and health professionals, you would want to store that information in a separate table, say person_info.
If you plan to have only 1 newsletter or very few types of newsletters (e.g. site updates, offers, etc), then you could store that info as one combined or one-per newsletter type in the person_info table.
But in my experience, the newsletter system should be its own set of tables in which the subscriptions are stores as rows, more like EAV rather than as columns. This reduces the amount of DDL needed when a new newsletter type is required by the business folks.

Related

How to extract relational data from a flat table using SQL?

I have a single flat table containing a list of people which records their participation in different groups and their activities over time. The table contains following columns:
- name (first/last)
- e-mail
- secondary e-mail
- group
- event date
+ some other data in a series of columns, relevant to a specific event (meeting, workshop).
I want to extract distinct people from that into a separate table, so that further down the road it could be used for their profiles giving them a list of what they attended and relevant info. In other words, I would like to have a list of people (profiles) and then link that to a list of groups they are in and then a list of events per group they participated in.
Obviously, same people appear a number of times:
| Full name | email | secondary email | group | date |
| John Smith | jsmith#someplace.com | | AcOP | 2010-02-12 |
| John Smith | jsmith#gmail.com | jsmith#somplace.com | AcOP | 2010-03-14 |
| John Smith | jsmith#gmail.com | | CbDP | 2010-03-18 |
| John Smith | jsmith#someplace.com | | BDz | 2010-04-02 |
Of course, I would like to roll it into one record for John Smith with both e-mails in the resulting People table. I can't rule out that there might be more records for same person with other e-mails than those two - I can live with that. To make it more complex ideally I would like to derive a list of groups, creating a Groups table (possibly with further details on the groups) and then a list of meetings/activities for each group. By linking that I would then have clean relational model.
Now, the question: is there a way to perform such a transformation of data in SQL? Or do I need to write a procedure (program) that would traverse the database and do it?
The database is in MySQL, though I can also use MS Access (it was given to me in that format).
There is no tool that does this automatically. You will have to write a couple queries (unless you want to write a DTS package or something proprietary). Here's a typical approach:
Write two select statements for the two tables you wish to create-- one for users and one for groups. You may need to use DISTINCT or GROUP BY to ensure you only get one row when the source table contains duplicates.
Run the two select statements and inspect them for problems. For example, it's possible some users show up with two different email addresses, or some users have the same name and were combined incorrectly. These will need to be cleaned up in order to proceed. There is great way to do this-- it's more or less a manual process requiring expert knowledge of the data.
Write CREATE TABLE scripts based on the two SELECT statements so that you can store the results somewhere.
Use INSERT FROM or SELECT INTO to populate the tables from your two SELECT statements.

Database structure for "products can be made of many products"

We are building a web database system and we need to allow some products to be made of other products. For example combining 2 or more products as a new product. We are using CakePhp and MySQL.
Here is the data structure diagram of our database:
https://www.dropbox.com/s/ksv22rt45uv69k9/Data%20Structure%20Diagram.png
Would we need to have self referencing products table or create a new table?
You can do either. There are pros and cons to both. Either way you will need a cross reference table.
The cross reference table can refer itself.
products in item
+---------------------+----------------------------+------------+
| product_identifier | product_identifier_child | quantity |
+---------------------+----------------------------+------------+
| 1 | 1 | 1 |
| 2 | 1 | 1 |
| 2 | 2 | 2 |
| 3 | 2 | 1 |
+---------------------+----------------------------+------------+
On the bright side, this method means you only have one table of data and only one new cross reference table, and you can add new products as you see fit (along with multiple of the same products, say, with a gift basket). On the downside, your table will be trying to do two different things at the same time. Products that have other products in them may not have a model number. Also, how will you determine whether to check the inventory table? Are you going to have inventory for products that are made out of products, or would you sooner check stock on individual products in order to see if your combo products are in stock? The latter is much more flexible, and you can still reserve inventory this way. It just allows all of your inventory to be in the same unit scale in your inventory table.
To add more flexibility, you can create another table, base products, which has values only the building block products are going to have.
base products
+--------------------------+----------+--------------+
| base product identifier | brand | model number |
+--------------------------+----------+--------------+
You could then attach your inventories to your base products table, and your cross reference table would be products to base products.
The negative here is that now instead of two tables, you have three. However, I am a fan of more tables with fewer columns thanks to increased flexibility. Even if the table tasks are not completely different, letting each table specialize completely can make things a lot easier.
There are numerous ways to go but optimal situation is the one that requires no data duplication and no NULL values. Without stressing yourself out about getting all the way there, try to keep your NULL values out of indexed columns and make sure your name values are only showing up in one place.

How to organize user credential in DB?

What would be the best approach to storing user credentials in MySQL database.
I mean structure, not the data (hash vs clean text).
I have site where we got
Root Admin (1)
Client Admin (1)
Client Sub-Admins (N)
Employer Admin (N)
Employer Sub-Admins (N)
Above users login at back end page
Users (N)
Users login at front end of the site
N - means unlimited
Guess my question is should i put all admins in same table? However employers are not so trusted as Client Admins.
If i put admins in different tables, how i do authentication in PHP? Take data from both tables and merge into array then look in array if user exists?
If you're only ever going to have a single root/client admin I would suggest simply storing their user_id values separately, possibly in a configuration file that is difficult to modify by something like SQL injection. Otherwise the following scheme should allow you a fair amount of flexibility to assign as many users to as many groups as you want.
TABLE users
user_id INT PK AUTO_INCREMENT
user_name VARCHAR
user_password VARCHAR
...
TABLE groups
group_id INT PK AUTO_INCREMENT
group_name VARCHAR
[possible permissions declarations,
or create a similar group_perms table]
...
TABLE user_group_map
user_id INT PK
group_id INT PK
One way to do it is to separate the authentication/user profile data from its possible array of roles. So, assign roles to your users. Hell, assign contexts to your roles. The way I see it, you have a 1-to-many relation between user and roles, in which the roles are assigned a context (Admin of Employers, Admin of Clients, General Admin...).
I would not use multiple tables just to separate users based on how much I trust them. After reading your question and comments in your case you would have to create individual tables for root admins, client admins, employer admins and regular users since your trust level is different for each group. Implementation / maintenance can become really ugly when you start coding even with only two tables...
You seem to be very determined to go with separate tables though and if you choose to do so there are techniques you can "hide" this, for example, create a view to merge these tables, use SQL union in your DAO, or read each table and merge the data programmatically, etc. Again, as you build your application you will most likely have issues with this design.
I would rather use a single table for users and introduce the concept of roles with a many-to-many relation between them. Upon user creation I would associate each user with a default role (eg. user root-admin has a role of root-admin, etc.) along with any other roles that they seem to fit (eg. user cleint-admin has an additional role of client-sub-admin, etc.) Based on the requirements there could be roles that do not relate to users directly, eg. guest, member, etc.
I would also introduce the concept of application contexts with an optional many-to-many relation to roles then initially associate the role root-admin with the application context all meaning that s/he has no restrictions. Additional contexts would be created based on business requirements (eg. role employer-admin is part of the context hire-employees, etc.)
When authorizing, a security manager component can grant / deny access based on the user and its associated roles / contexts with additional logic included if necessary (eg. user is disabled).
Your next concern was that you have additional data for certain users which does not apply to others. In order to resolve this I would introduce the profiles table with an optional one-to-one relation to the users table (not every user has a profile, eg. user root-admin does not).
Schema (draft):
__________________ __________________
|USERS | |ROLES |
|==================| |==================|
|id | |id |
|username | 1..* 1..* |name |
|password | -------------- |description |
|failedattempts | |... |
|disabled | | |
|... | | |
|__________________| |__________________|
| 1 | 0..*
| |
| |
| |
| 0..1 | 0..*
__________________ __________________
|PROFILES | |CONTEXTS |
|==================| |==================|
|id | |id |
|firstname | |name |
|lastname | |description |
|email | |... |
|dob | | |
|... | | |
|__________________| |__________________|
I've described a user and group permission system in this post (ignore the title -- the original question was poorly worded):
Applying column permissions for a table over a trigger

Database Design - Linking student to teacher

Still working on a web application as a school project, and it just seems to keep expanding.
I have to add a layer for teachers so they can manage and coach students through the application. So, I have to link teachers to their students.
I was wondering what the best way would be to do this. I have one table for all users at the moment. The bare basics of this table are:
id | email | firstname | lastname | role
1 | s#s.s | dromiceio | mimus | 1
2 | d#d.d | tyranno | saurus | 2
3 | a#a.a | utah | raptor | 1
Role is the number I assign to them to give them certain permissions. 1 = student, 2 = teacher, 3 = admin.
Assuming that one student has one teacher but one teacher has many students, what would be the best way to design my database table?
I was thinking of creating a new table and just putting the student/teacher ids in it:
For example, if teacher Tyranno Saurus (id 2) has the two students in the table above linked to him, I would make a table like this:
pk_id | teacherid | studentid
1 | 2 | 1
2 | 2 | 3
That way, I would know that teacher Tyranno (id 2) has two students, namely the student with userid 1 and userid 3.
Then again, I have never really worked on anything like this so I was wondering if anyone could give me some insight about this and if it's possible to do this in a better way.
I'm building my app in PHP (CodeIgniter) with MySQL; if that's of importance.
Thanks a lot.
If a student has zero-or-one teacher coaching them, then I would suggest adding a CoachID column to the student table that is a foreign-key to that particular teacher. The intermediate table you've suggested doesn't do anything to simplify this simple relationship, it actually makes it that little bit more complicated.
If you were tying students to classes (where each class has multiple students and each student takes multiple classes) then an intermediate many-to-many mapping table would be a must.

What is the best way to handle these MySQL database relationsships?

I'm building a small website that let users recommend their favourite books to eachother. So I have two tables, books and groups. A user can have 0 or more books in their library, and a book belongs to 1 or more groups. Currently, my tables look like this:
books table
|---------|------------|---------------|
| book_id | book_title | book_owner_id |
|---------|------------|---------------|
| 22 | something | 12 |
|---------|------------|---------------|
| 23 | something2 | 12 |
|---------|------------|---------------|
groups table
|----------|------------|---------------|---------|
| group_id | group_name | book_owner_id | book_id |
|----------|------------|---------------|---------|
| 231 | random | 12 | 22 |
|----------|------------|---------------|---------|
| 231 | random | 12 | 23 |
|----------|------------|---------------|---------|
As you can see, the relationsships between users+books and books+groups are defined in the tables. Should I define the relationsships in their own tables instead? Something like this:
books table
|---------|------------|
| book_id | book_title |
|---------|------------|
| 22 | something |
|---------|------------|
| 23 | something2 |
|---------|------------|
books_users_relationsship table
|---------|------------|---------|
| rel_id | user_id | book_id |
|---------|------------|---------|
| 1 | 12 | 22 |
|---------|------------|---------|
| 2 | 12 | 23 |
|---------|------------|---------|
groups table
|----------|------------|
| group_id | group_name |
|----------|------------|
| 231 | random |
|----------|------------|
groups_books_relationsship table
|----------|---------|
| group_id | book_id |
|----------|---------|
| 231 | 22 |
|----------|---------|
| 231 | 23 |
|----------|---------|
Thanks for your time.
The second form with four tables is the correct one. You could delete rel_id from books_users_relationsship as primary key might be composite with both user_id and book_id, just like in groups_books_relationsship table.
You do not need a "relationship table" to support a relationship. In Databases, implementing a Foreign Key in a child table defines the Relation between the parent and the child. You need tables only if they contain data, or to resolve a many-to-many relationship (and that has no data other than the Primary Keys of the parents).
The second problem you are facing, the reason the Relations become complex, and even optional, is due to the first two tables not being Normalised. Many problems ensue from that.
if you look closely at book, you may notice that the same book (title) gets repeated
likewise, there is no differentiation between (a) a book in terms of its existence in the world and (b) a copy of a book, that is owned by a member, and available for borrowing
eg. the review is about an existing book, once, and applies to all copies of a book; not to an owned book.
your "relationship" tables also have data in them, and the data is repeated.
all this repeated data needs to be maintained and kept in synch.
all those problems are eliminated if the data is Normalised.
Therefore (since you are seeking the "best way"), the sequence is to normalise the data first, after which (no surprise) the Relations are easy and not complex, and no data is repeated (in either the tables or the relations).
when Normalising, it is best to model the real world (not the entire real world, but whatever parts of it that you are implementing in the database). That insulates your database from the effects of change, and functional extensions to it in future do not require the existing tables to be changed.
It is also important to use accurate names for tables and columns, for the same reason. group in non-specific and will cause a problem in future when you implement some other form of grouping.
The relations can be now defined at the correct "level", between the correct tables.
The need to stick an Id column on everything that moves severely hinders your ability to understand the data and thus the Normalisation process, and robs the database of Relational power.
Notice that the existing keys are already unique and meaningful, short and efficient, no additional surrogate keys (and their additional index) is required.
ReviewerId, OwnerId and BorrowerIdare allMemberIds`, as Foreign Keys, showing the explicit Role in which they are used.
Note that your problem space is not as simple as you think, it is used as a case study and shipped with tutorials for SQL (eg. MS SQL, Sybase).
Social Library Data Model
Readers who are unfamiliar with the Standard for Modelling Relational Databases may find IDEF1X Notational useful.
I have provided the structure required to support borrowing, to again illustrate how easy it is to implement Relations on Normalised data, and to show the correct tables upon which borrowing depends (it is not between any book and any person; only owned book can be borrowed).
These issues are very important because they define the Referential Integrity of the database.
It is also important to implement that in the database itself, which is the Standard location (rather than in app code all over the place). Declarative Referential Integrity is part of IEC/ISO/ANSI Standard SQL. And the question has a database design tag.
Referential Integrity cannot be defined or enforced in some databases that do not fully implement the SQL Standard (sometimes it can be defined but it is not enforced, which is confusing). Nevertheless, you can design and implement whatever parts of a database your particular database supports.