Is it possible to normalize the table so that it can contain one Value in one row? - mysql

I have a table containing three column BusNo, BusRoute & BusStop where BusStop column contain multiple comma separated values. I want to normalize it so that the table contain one stop in one Row. Ex.
BusNo BusRoute BusStop
1 Rajendra Nagar to Noida Apsara,Shahadara,Shakarpur,Mother Dairy
I want to make the stops in multiple row would it be good approach I have more that 1000 BusNo here.

My suggestion would be to have two new tables: BusStops and BusRouteBusStops.
BusStops will have one line for each bus stop, containing at least two columns: StopNumber and StopName.
BusRouteBusStops will be the table that links the BusRoute table with the BusStops table. Each line in this table will have a primary key from BusRoutes and from BusStops.
The idea is to keep the bus stops in a table, regardless of if and where they are used. That way you can use a single stop in however many routes you want. Also, if you decide to remove a stop from all the routes, it is still kept and is available for use for new routes.
If you want to represent the order of the bus stops in the route, it can be added as a column to the BusRouteBusStops table.
Tables example:
Table BusRoutes - primary-Key(BusNo)
===============
BusNo | BusRoute
1 | Rajendra Nagar to Noida
Table BusStops - primary-Key(StopNumber)
===============
StopNumber | StopName
1 | Apsara
2 | Shahadara
3 | Shakarpur
4 | Other Stop
5 | Mother Dairy
Table BusRouteBusStops - primary-Key(BusNo+StopNumber)
===============
BusNo | StopNumber | stpoOrder
1 | 1 | 1
1 | 2 | 2
1 | 3 | 3
1 | 5 | 4
A query to get all the bus numbers that go through a given stop (say: Apsara), using MySql syntax, will be:
SELECT BR.*
FROM BusRoutes BR, BusStops BS, BusRouteBusStops BRBS
WHERE BR.BusNo=BRBS.BusNo
AND BS.StopNumber=BRBS.StopNumber
AND BS.StopName="Apsara"

To resolve a m:n relation, you normally use an additional table. As you have everything in one table right now, that means two additional tables for you.
Table structure
bus_stop: id, name
bus_route: id, description
stop_to_route_relation: bus_route, bus_stop
Example
bus_stop
--------------------
| id | name |
--------------------
| 1 | CityA |
--------------------
| 2 | CityB |
--------------------
| 3 | CityC |
--------------------
bus_route
-----------------------------
| id | bus_no | description |
-----------------------------
| 1 | 5 | CityA to B |
-----------------------------
| 2 | 5 | CityA to C |
-----------------------------
stop_to_route_relation
------------------------
| bus_route | bus_stop |
------------------------
| 1 | 1 |
------------------------
| 1 | 2 |
------------------------
| 2 | 1 |
------------------------
| 2 | 3 |
------------------------
Example query
select
br.bus_no,
bs.name
from
bus_route br
left join stop_to_route_relation str on (br.id = str.bus_route)
left join bus_stop bs on (str.bus_stop = bs.id);

If you want to normalize BusStop field then you need to make a new table for it. Like this:
Table: Bus
===================================
| BusNo | BusRoute
===================================
| 1 | Rajendra Nagar to Noida
===================================
Table: BusStop
--------------------------
| BusNo | BusStop
--------------------------
| 1 | Apsara
--------------------------
| 1 | Shahadara
--------------------------
| 1 | Shakarpur
--------------------------
| 1 | Mother Dairy
--------------------------
In the BusStop table the BusNo is the Foreign Key that links it to Bus table.
You mentioned that you have 1000 BusNo so I guess it will require a lot of resources since normalizing it will need more rows for saving the BusStop for each BusNo. For instance, each BusNo has 5 BusStops then your new table for BusStop will approximately have 1000 x 5 rows (Your saving every BusStop of Bus in the table). The advantage that I see here is you can do more queries in normalizing it. You weigh the pros and cons in deciding. Goodluck.

Related

MySql add relationships without creating dupes

I created a table (t_subject) like this
| id | description | enabled |
|----|-------------|---------|
| 1 | a | 1 |
| 2 | b | 1 |
| 3 | c | 1 |
And another table (t_place) like this
| id | description | enabled |
|----|-------------|---------|
| 1 | d | 1 |
| 2 | e | 1 |
| 3 | f | 1 |
Right now data from t_subject is used for each of t_place records, to show HTML dropdowns, with all the results from t_subject.
So I simply do
SELECT * FROM t_subject WHERE enabled = 1
Now just for one of t_place records, one record from t_subject should be hidden.
I don't want to simply delete it with javascript, since I want to be able to customize all of the dropdowns if anything changes.
So the first thing I though was to add a place_id column to t_subject.
But this means I have to duplicate all of t_subject records, I would have 3 of each, except one that would have 2.
Is there any way to avoid this??
I thought adding an id_exclusion column to t_subject so I could duplicate records only whenever a record is excluded from another id from t_place.
How bad would that be?? This way I would have no duplicates, so far.
Hope all of this makes sense.
While you only need to exclude one course, I would still recommend setting up a full 'place-course' association. You essentially have a many-to-many relationship, despite not explicitly linking your tables.
I would recommend an additional 'bridging' or 'associative entity' table to represent which courses are offered at which places. This new table would have two columns - one foreign key for the ID of t_subject, and one for the ID of t_place.
For example (t_place_course):
| place_id | course_id |
|----------|-----------|
| 1 | 1 |
| 1 | 2 |
| 1 | 3 |
| 2 | 1 |
| 2 | 2 |
| 2 | 3 |
| 3 | 1 |
| 3 | 3 |
As you can see in my example above, place 3 doesn't offer course 2.
From here, you can simply query all of the courses available for a place by querying the place_id:
SELECT * from t_place_course WHERE place_id = 3
The above will return both courses 1 and 3.
You can optionally use a JOIN to get the other information about the course or place, such as the description:
SELECT `t_course`.`description`
FROM `t_course`
INNER JOIN `t_place_course`
ON `t_course`.`id` = `t_place_course`.`course_id`
INNER JOIN `t_place`
ON `t_place`.`id` = `place_id`

Application specific MySQL table Structure

I have a question about my DB table structure. I want to know if i'm on the right track or if I have missed a good alternative. Here is the case:
To make it easy to read, I haven't pasted the full contents as my question is only about the structure.
2 tables:
1: id (AI), task
2: id, name, task
Table 1 presents dynamic check-boxes which can be altered by an admin panel so the contents would be like this
1 task1
2 task2
5 task5
(3 & 4 are missing cause the administrator deleted those records).
In table number two are the people who should do the tasks from table 1. And the goal is that the tasks wich are not checked will be displayed.
So the contents of table 2 would be:
1 Name1 1,5
2 Name2 1,2
3 Name3 1,2,5
The numbers in table 2 represent the checked boxes from table 1. So with a query i can compare the numbers from table 2 with the id's from table 1 and display the missing ids as "todo".
In my opinion this looks very overdone, and there must be an easier way to create dynamic options which can be compared and stored as a todo.
Suggestions are welcome!
I suggest you to use basic structure for many-to-many relationship:
tasks users user_tasks
+----+-----------+ +----+-------+ +---------+---------+
| id | name | | id | name | | user_id | task_id |
+----+-----------+ +----+-------+ +---------+---------+
| 1 | Buy milk | | 1 | John | | 1 | 2 |
| 2 | Get drunk | | 2 | Tim | | 3 | 2 |
| 3 | Have fun | | 3 | Steve | | 2 | 4 |
| 4 | Go home | +----+-------+ | 3 | 4 |
+----+-----------+ +---------+---------+
And you can fetch unassigned tasks using following query:
SELECT
tasks.*
FROM
tasks
LEFT JOIN
user_tasks
ON (tasks.id = user_tasks.task_id)
WHERE
user_tasks.user_id IS NULL
You also can fetch users who have no assigned tasks:
SELECT
users.*
FROM
users
LEFT JOIN
user_tasks
ON (users.id = user_tasks.user_id)
WHERE
user_tasks.user_id IS NULL
Hope this will help you.

mysql: how to split list field

I have a table which only contains id and a field whose data is a list of data. e.g.
--------------
| id | data |
| 1 | a,b,c,d|
| 2 | a,b,k,m|
---------------
I guess it's not a good design that put a list data in a field, so I want to know how can I redesign it?
As per me you need two tables i.e. Master and Transaction tables only when some details are gonna be same for every records and some are gonna be changing. In your case if there are not any other thing related to your id field is gonna be same you can carry on with one table and with following structure.
--------------
| id | data |
| 1 | a |
| 1 | b |
| 1 | c |
| 1 | d |
| 2 | a |
| 2 | b |
| 2 | k |
| 2 | m |
---------------
BUT if there are any other things related to the id fields that is gonna be same for same id records you will have to use two tables.
like following case. there are 3 fields id, name and data.
and you current table looks something like
--------------------------
| id | name | data |
| 1 | testname | a,b,c,d|
| 2 | remy | a,b,c,d|
--------------------------
your new table structure should look like.
table 1 Master
-----------------
| id | name |
| 1 | testname |
| 2 | remy |
-----------------
Table 2 Transaction
--------------
| id | data |
| 1 | a |
| 1 | b |
| 1 | c |
| 1 | d |
| 2 | a |
| 2 | b |
| 2 | k |
| 2 | m |
---------------
For better database management we might need to normalize the data.
Database normalization is the process of organizing the fields and tables of a relational database to minimize redundancy and dependency. Normalization usually involves dividing large tables into smaller (and less redundant) tables and defining relationships between them. The objective is to isolate data so that additions, deletions, and modifications of a field can be made in just one table and then propagated through the rest of the database via the defined relationships. You can find more on below links
3 Normal Forms Database Tutorial
Database normalization
If you have only those two fields in your table then you should have only 1 table as below
id | data
with composite primary key as PRIMARY KEY(id,data) so that there won't be any duplicate data for the respective ID.
The data would be like this
id | data
1 | a
1 | b
1 | c
1 | d
2 | a
2 | b
2 | k
2 | m
You will need another table which can be of the ONE to MANY type.
For e.g. you could have another table datamapping which would have data and ID column where the ID column is a FOREIGN KEY to the ID column of the data table.
So according to your example there would be 4 entries for ID = 1 in the datamapping table.
You will need two tables with a foreign key.
Table 1
id
Table 2
id
datavalue
So the data looks like:
Table 1:
id
1
2
3
Table 2:
id | data
1 | a
1 | b
1 | c
1 | d
2 | a
2 | b
2 | k
2 | m
You are correct, this this is not a good database design. The data field violates the principle of atomicity and therefore the 1NF, which can lead to problems in maintaining and querying the data.
To normalize your design, split the original table in two. There are 2 basic strategies to do it: using non-identifying and using identifying relationship.
NOTE: If you only have id in the parent table, and no other FKs on it, and parent cannot exist without at least one child (i.e. data could not have been empty in the original design), you can dispense with the parent table altogether.

Data Entry Tracking (Database Design)

I have developed a website (PHP) that allow staffs to add records on to our system.
Staffs will be adding thousands of records into our database.
I need a way to keep track of what record have been done and the process/status of record.
Here a number of Teams I could think of:
Data Entry Team
Proof Reading Team
Admin Team
When staff (Data Entry Team) completed a record - he/she will then click on the Complete button. Then somehow it should asssign to 'Proof Reading Team' automatically.
A record need to be checked twice from a Proof Reading Team. If StaffB finish proof reading then another member from Proof Reading Team need to check it again.
When Proof reading is done, Admin Team will then assign "Record Completed"
In a few months later record might need to be updated (spelling mistake, price change, etc) - Admin might to assign record to Data entry team.
Is this good data entry management solution? How do I put this into Database Design perspective?
Here what I tried:
mysql> select * from records;
+----+------------+----------------------+
| id | name | address |
+----+------------+----------------------+
| 1 | Bill Gates | Text 1 Text Text 1 |
| 2 | Jobs Steve | Text 2 Text 2 Text 2 |
+----+------------+----------------------+
mysql> select * from staffs;
+----+-----------+-----------+---------------+
| id | username | password | group |
+----+-----------+-----------+---------------+
| 1 | admin1 | admin1 | admin |
| 2 | DEntryA | DEntryA | data_entry |
| 3 | DEntryB | DEntryB | data_entry |
| 4 | PReadingA | PReadingA | proof_reading |
| 5 | PReadingB | PReadingB | proof_reading |
+----+-----------+-----------+---------------+
mysql> select * from data_entry;
+----+------------+-----------+------------------------+
| id | records_id | staffs_id | record_status |
+----+------------+-----------+------------------------+
| 1 | 2 | 3 | data_entry_processiing |
| 2 | 2 | 3 | data_entry_completed |
| 3 | 2 | 4 | proof_read_processing |
| 4 | 2 | 4 | proof_read_completed |
| 5 | 2 | 5 | proof_read_processing |
| 6 | 2 | 5 | proof_read_completed |
+----+------------+-----------+------------------------+
Is there alternative better solution of database design?
i think design it's well done. but may be you want to separate group into groups table, and record_status into status table. If you're storing a lot of records you would store a lot of useless information, at least create an enum type for record_status field and group field
table: groups
id - name 1 - admin 2 - data_entry 3 - proof_reading
...
table: status
id - name 1 - data_entry_processing ...
and if you want the users to be in different groups at a time, you could create users_group table
table: user_groups
group_id - user_id 1 - 1 2 - 1 1 - 4 3 -
4 4 - 4 ....
Hope this helps

Special unique columns

I have a situation where a website (a source) has multiple feeds (category separated)
Feed Table
feed_id | source_id | feed_url
1 | 1 | http://example.com/rss?category=1
2 | 1 | http://example.com/rss?category=5
3 | 2 | http://textample.com/rss
Item Table
item_id | true_id | feed_id
1 | 1332 | 1
2 | 76549 | 1
3 | 76549 | 2
4 | 76549 | 3
the true id is the id I try to get from the source site.
I want the item id 2 & 3 are the same, because they share the same source (example.com), item 4 is not the same because it has a different source (textample.com)
Is there a way I can enforce that consistency, without adding the source id to the Item Table?
RUN
ALTER TABLE `itemTable` ADD UNIQUE (`feed_id`);