Multi-user web app - Database design - database

I am going to be developing a multi-user web app where users will record every day whether or not they have completed various tasks. The tasks are repeated every day, eg: Every day XYZ needs to be done.
Not all users will have the same tasks to complete each day. There will likely be a database table containing all possible tasks. When a new user signs up on the web, they will select the tasks that apply to them by creating a profile for themselves.
Each day the user will then record whether or not they completed their respective tasks. Following that, there will be in depth reporting and historical stats not just on a users own task history,...but also globally to look for trends.
Im just looking for any suggestions on how to design the database (in general terms). Would it be ok to have a task table that contains all the tasks. Then when a new user creates their own profile online, a brand new table is created with their profile information and the tasks that they have selected. Each unique user profile table will then contain an ongoing history of tasks completed each day.
Or is there a better way to design this?
Edit: Or would a better idea to be to have something like the below:
Task history table:
PersonID | Date | Task1 | Task2 | Task3 | Task 4
001 | 24Jan15 | Complete | Complete | |
002 | 24Jan15 | | Complete | Complete | Not Complete
003 | 24Jan15 | Not Complete | | |
So there would be one table containing all the users (and the tasks they've chosen), another table containing all possible tasks, and lastly the above table recording the task history each day.
The only issue here is that not every task is applicable to every person. So there will be blanks. Not sure if that matters.
As you can no doubt tell, im a beginner. So any advice would be appreciated.

It is almost never a good idea to create new tables dynamically to hold subsets of the data. Data for different users should go in the same set of tables, with some field identifying the user. There is no good reason to have hundreds of tables that are all identical except that one is for some key value A, the next is for key value B, etc. Just add the key field to the table.
As a_horse_with_no_name says, numbered columns is a strong sign that you are doing it wrong. There are many reasons why this is a bad idea. Among them: If you have one column for each task, what happens when a new task is added? Instead of just adding a new record, now you have to add a new column to the table, and update all the existing records. Also, it makes queries very complicated. A query like "what tasks were done today" requires a separate test for every column, instead of one test on a single "task" column.
From what you've said, here's my first thought on how this should look:
Task table
(task_id, task_name)
This lists all the tasks of interest.
User table
(user_id, user_name)
This lists all the users.
Assigned_Task table
(user_id, task_id)
This relates users to tasks. There will be one record in this table for each task for each user. That is, if Alice is user 1 and she is supposed to do tasks 1, 2, and 3; and Bob is user 2 and he is supposed to do 2 and 4, then there will be records (1,1), (1,2), (1,3), (2, 2), and (2,4).
(Note: You might have an assigned_task_id field for this table to be the primary key, or the PK could be user_id + task_id, as that must be unique.)
Task_Status table
(user_id, task_id, task_date, completed)
This will have one record for each user/task combination, for each day. So after 30 days, if Alice has 3 tasks, there will be 3 x 30 = 90 records for her, 3 for each day times 30 days.
(You might have a task_status_id as the PK, or you might use user_id + task_id + task_date. Keys with more than 2 fields tend to be a pain so I'd probably create a task_status_id. Whatever.)
Any of these tables might have additional fields if there's other information you need. Like the User table might have employee number, phone number, department, etc.
Then a question like, "What tasks were not completed yesterday?" is easily answered with this query:
select user.name, task.name
from task_status
join user on user.user_id=task_status.user_id
join task on task.task_id=task_status.task_id
where task_date=#date
and completed=0
How many tasks were completed today?
select count(*)
from task_status
where date=#date and completed=1
Etc.

Related

Create a relationship across multiple tables that allows only one entry per date

I am trying to create a database that will be used by multiple teams in my company that displays their daily stats.
When you open up the database I have a combo box that allows you to select your team name. Once you make your selection, your form appears with your team stats for the day. (In reality it's just one form that has a subform with a query. The query is updated when you select your team from the combo box)
Each team has their own separate set of stats for each day and they are only allowed one entry per day. Not every single team has the same category of stats. This is an example of some of my tables
Quality Stats Table:
Team Name | Daily # | Actual # | Goal # | DateOfEntry
Productivity Table:
Team Name | Percentage | DateOfEntry
Stop Ship Table:
Team Name | Yes/No | DateOfEntry
How do I make it so that each team can only have one entry in each table per day?
I have my Team Names linked across all the tables, but I am having a hard time enforcing the one entry per date restriction
I am very new at access and I am still trying to figure it out. I would greatly appreciate it if someone can point me in the right direction
Create a multiple-field unique index on each of those tables. Here is an example for the Quality Stats table ...
strSQL = "CREATE UNIQUE INDEX idxQualTeamDate ON [Quality Stats] ([Team Name], DateOfEntry)"
CurrentProject.Connection.Execute strSQL
The same thing can also be done through the Access user interface. If you prefer to go that route, it might still be helpful to execute the CREATE UNIQUE INDEX statement I gave you and then open the table in Design View to see how Access presents it there.

How do i prevent the duplicate id from the imported table in MariaDB?

(Before that, i apologize for my bad English)
I have study cases like this:
I am currently having a trouble with my Web Application. I made a Web application for a certain company. I made the app using CodeIgniter 3.
I built the database using Maria DB. For the id in each table, i am using Auto-increment id for my application database for each table. I usually deploy the web app to the cloud server (sometimes the company have their own dedicated server, but sometimes haven't ). One day, there is a company that they don't want to deploy the app that i have made before to the cloud ( for the security purposes they said ).
This company wanted to deploy the app to the employee's PC personally in the office, while the pc for each employee not connected to each other ( i.e stand alone pc/personal computer/employee's Laptop ). They said, for every 5 months, they would collect all of the data from employee's personal computer to company's data center, and of course the data center are no connected to the internet. I told them that's not the good way to store their data. ( because the data will be duplicate when i am trying to merge all of the data into one, since my column id for every table are in auto-increment id, and it's a primary key). Unfortunately, The company still want to kept the app that way, and i don't know how to solved this.
They have at least 10 employees that would used this web app. According that, I have to deploy the app to the 10 PC personally.
Additional info : Each employee have their own unique id which they got from the company, and i made the auto_increment id for each employee, just like the table below:
id | employee_id | employee_name |
1 | 156901010 | emp1
2 | 156901039 | emp2
3 | 156901019 | emp3
4 | 156901015 | emp4
5 | 156901009 | emp5
6 | 156901038 | emp6
The problem is whenever they fill the form from that application, some of the table are not stored the employee's id but the new id that come from increment id.
For example electronic_parts table. They have the attribute like below:
| id | electronic_part_name | kind_of_electronic_part_id |
if the emp1 fill the form from the web app , the table's content would like below.
| id | electronic_part_name | kind_of_electronic_part_id |
| 1 | switch | 1 |
and if the emp2 fill the form from the web app , the table's content would like below.
| id | electronic_part_name | kind_of_electronic_part_id |
| 1 | duct tape | 10 |
When i tried to merge the contents of the table into the data center it would falling apart because the duplicate id.
It's getting worst when i think about my foreign key in other tables.. like for example the customer_order table.
The table for customer_order column looks like below (just a sample, not the actual table, but similar).
|id | customer_name | electronic_parts_id | cashier(a.k.a employee_id, the increment id one, not the id that employee got from a company as i described above ) |
| 1 | Henry | 1 | 10 |
| 2 | Julie | 2 | 9 |
Does anyone know how to solved this problem ? or can someone suggest/recommend me some good way to solved this ?
NOTE: Each Employees have their own database for their app, so the database is not centralized, it's a stand-alone database, that means, i have to installed the database to the employee's pc one by one
This is an unconventional situation and you can have an unconventional solution.
I can suggest you two methods to solve this issue.
Instead of using autoincrement for primary key generate a UUID and use it as the primary key. Regarding the probability of duplicates
in random UUIDs: Only after generating 1 billion UUIDs every second
for the next 100 years
In CodeIgniter you could do this with the following code snippet.
$this->db->set('id', 'UUID', FALSE);
This generates a 36 characters hexadecimal key (with 4 dashes
included).
ac689561-f7c9-4f7e-be94-33c6c0fb0672
As you can see it has dashes in the string, using the CodeIgniter DB
function will insert this in the database with the dashes, it still
will work. If it does not look at clean, you could remove and
convert the string to a 32-char key.
You can use the following function with the help of [CodeIgniter
UUID library][1].
function uuid_key {
$this->load->library('uuid');
//Output a v4 UUID
$id = $this->uuid->v4();
$id = str_replace('-', '', $id);
$this->db->set('id', $id, FALSE);
}
Now we have a 32-byte key,
ac689561f7c94f7ebe9433c6c0fb0672
An alternate unconventional method to tackle the situation is by
adding function to log all Insert, Update, Delete queries processed
in the site to a file locally. By this way, in each local
implementation will generate a log file with an actual list of
queries that modify the DB over time in the right sequential order.
At any point in time, the state of the database is the result of the
set of all those queries happened in the past till that date.
So in every 5 months when you are ready to collect data from
employees personal computer, instead of taking data dump, take this
file with all query log.(Note: Such a query log won't have
auto-increment id as it will be created only in the real time when
it is executed towards a Database. )
Use such files to import data to your datacenter. This will not
conflict as it will generate autoincrements in your data center in
real time. (Hope you do not have to link your local to data center
at any point of time in future)
[1]: https://github.com/Repox/codeigniter-uuid
Is that id used in any other tables? It would probably be involved in a JOIN. If so, you have a big problem of unraveling the ids.
If the id is not used anywhere else, then the values are irrelevant, and the rows can be renumbered. This would be done (roughly speaking) by loading the data from the various sources into the same table, but not include the id in the load.
Or, if there is some other column (or combination of columns) that is UNIQUE, then make that the PRIMARY KEY and get rid of id.
Which case applies? We can pursue in more detail. Please provide SHOW CREATE TABLE for any table(s) that are relevant.
In my first case (where id is used as a FK elsewhere), do something like this:
While inserting the rows into the table with id, increment the values by enough to avoid colliding with the existing ids. Then do (in the same transaction):
UPDATE the_other_table SET fk_id = fk_id + same_increment.
Repeat for each other table and each id, as needed.
I think your problem come from your database... you didn't design it well.
it's a bug if you have an id for two difference users .
if you just made your id field unique in your database then two employee wouldn't have a same id so your problem is in your table design .
just initiate your id field like this and your problem will be solved .
CREATE TABLE [YOUR TABLE NAME](
[ID] int NOT NULL IDENTITY(1,1) PRIMARY KEY,
....
Is it required for the id to be an integer? if not may be you can use a prefix on the id so the input for each employee will be unique in general. that means you have to give up the auto increment and just do count on the table data (assuming youre not deleting any of the records.)
You may need to write a code in PHP to handel this. If other table is already following unique/primary key based than it is fine.
You can also do it after import.
like this
Find duplicates in the same table in MySQL

How would I design this database?

Every day I want to track how many "clicks"(int) a certain object in my database gets.
Now an int in the object called clicks obviously wouldn't help since I couldn't track the date of the clicks.
What way would be the smartest to store the daily clicks?
Keep the VisitedDate column in your tracking table.
RecordID INT Identity
ItemID INT
VisitedDate DateTime
IPAddress varchar(30)
Once you have the records, you can query and get the results for visits on a specific day/ month etc...
Create a table as Shyju suggests (ip address is optional), and yes it will grow fast but if it becomes a problem you can rollup the data to a weekly (or monthly, or yearly) rollup table where it stores the total for that item, for that time period.
Best to always initially store the data at this lowest-level and roll up/archive to summary tables as needed down the road, because if you store the data initially at the roll up level you have lost that detail forever - tracking at the detail level keeps all your options open.
There are workarounds for performance if you need them, there are no workarounds to recreate data you never stored.
I insert or update on the go, on the clicks table.
Clicks
(Product_id | Vendor_id | User_id)[unique] | Clicks | Created_at
Insert if the (Product_id | Vendor_id | User_id) combintaion does not exist. Update (+1 clicks), if that combination already exists.
I wouldn't worry about the performance right now, during the early stage.
If you still worry about it,
Use a javascript request and write the (Product_id | Vendor_id | User_id)[unique] | Clicks | Created_at into a textfile, onclick.
In the EOD, load the information in the file into clicks table.

what is the best table structure for keeping several combo box(list box)

I have several list boxes in my web application that user has to fill. Administrator can add/remove/edit values in the combo box from controle panel. so problem is what is the best way to keep these combo box in database.
one way is keeping each table for each combo box. I think this is very easy to handle but I will have to create more than 20 tables for each combo/list box.And I think whether it is good practice to do so.
anotherway is keeping one table for all combo box. But I am worring when deleting data in this case.
If I want to remove India from countr coloum in combo box table, then I will be in problem. I may have to update it to null or some otherway and have to handel this in programming side.
Am I correct. can you help me ?
I think you just should create a table with 3 fields. First field is the id, second is the name and the last is the foreign key. For example:
combo_box_table
id - name - box
1 - Japan - 1
2 - India - 1
3 - Scotland - 2
4 - England - 3
you just have to play with query, each box represent the last field. 1 represent combo box 1 and 2 represent combo box 2 etc.
select * from combo_box_table where box = 1
if you want to delete india the query is just delete from combo_box_table where id = 2
May this help
Another possibility would be to save the combo box data as an array or a json string in a single field in your table, but whether you want to do this or not depends on how you want your table to function and what you application is. See Save PHP array to MySQL? for further information.
EDIT:
I'm going to assume you have a combo-box with different countries and possibly another with job titles and others.
If you create multiple tables then yes you would have to use multiple SQL querys, but the amount of data in the table would be flexible and deleting would be a one step process:
mysqli_query($link,"DELETE FROM Countries WHERE Name='India'");
With the json or array option you could have one table, and one column would be each combo-box. This would mean you only have to query the table once to populate the combo-boxes, but then you would have to decode the json strings and iterate through them also checking for null values for instance if countries had 50 entries but job titles only had 20. There would be some limitations on data amount as the "text" type only has a finite amount of length. (Possible, but a nightmare of code to manage)
You may have to query multiple times to populate the boxes, but I feel that the first method would be the most organized and flexible, unless I have mis-interpreted your database structure needs...
A third possible answer, though very different, could be to use AJAX to populate the combo-boxes from separate .txt files on the server, though editing them and removing or adding options to them through any way other than manually opening the file and typing in it or deleting it would be complex as well.
Unless you have some extra information at the level of the combo-box itself, just a simple table of combo-box items would be enough:
CREATE TABLE COMBO_BOX_ITEM (
COMBO_BOX_ID INT,
VALUE VARCHAR(255),
PRIMARY KEY (COMBO_BOX_ID, VALUE)
)
To get items of a given combo-box:
SELECT VALUE FROM COMBO_BOX_ITEM WHERE COMBO_BOX_ID = <whatever>
The nice thing about this query is that it can be satisfied by a simple range scan on the primary index. In fact, assuming the query optimizer of your DBMS is clever enough, the table heap is not touched at all, and you can eliminate this "unnecessary" heap by clustering the table (if your DBMS supports clustering). Physically, you'd end-up with just a single B-Tree representing the whole table.
Use a single table Countries and another for Job Descriptions setup like so:
Countries
ID | Name | JobsOffered | Jobs Available
_________________________________________
1 | India | 1,2,7,6,5 | 5,6
2 | China | 2,7,5, | 2,7
etc.
Job Descriptions
ID | Name | Description
___________________________________
1 | Shoe Maker | Makes shoes
2 | Computer Analyst | Analyzes computers
3 | Hotdog Cook | Cooks hotdogs well
Then you could query your database for the country and get the jobs that are available (and offered) then simply query the Job Description table for the names and display to the user which jobs are available. Then when one job is filled or is opened all you have to do is Update the contry table with the new jobID.
Does this help? (In this case you will need a separate table for each combo-box, as suggested, and you have referencing IDs for the jobs available)

How to create a timer that counts up with server side controls, but client side display?

I want to write a timer that counts up, no preference of code, that has controls to start and stop the timer on my server, but displays the time on the clients computer. I can offer more information if needed.
Thanks!
What you need is a database. I'd go with MySQL (http://dev.mysql.com/downloads/mysql/), since it's good and free. If you're paying for hosting you might already have access to a database though.
Then you need some tables to store the necessary info. How you create them depends on your database, but I'll make a rough outline.
You'd typically have a customer table with info about your customer:
| Customer Id | Customer name | Contact person | Phone | E-mail |
Then a table for each of the project your doing for your customer (here you'll have a foreign key to the customer table):
| Project Id | Customer Id | Cost per hour | Estimated hours | Start date | Finish date |
And here's the table that will be updated whenever you start or stop working on the project. There will be a new row in this table every time you "stop the timer" on the project (project Id is a foreign key to the previous table. Customer id is optional, since you can get at the customer through the second table):
| Session Id | Project Id | Customer Id | Start | Stop |
Here "start" and "stop" are timestamps. Session id is an auto incremented id. Each time you start the timer, that corresponds to inserting a new row into the table with the current time in the start field. Each time you stop the timer, that corresponds to setting the current time in the stop field for the only row with the current project where the stop date is null.
When the customer wants to know the total time spent on the project so far, that's a matter of summing all the intervals (stop - start) on the projects.
To make use of any of this, you need to make a framework in some kind of programming language. I prefer perl myself, but php is probably your best bet, since it's well suited for these kinds of things.
It's hard to go into more specifics until you've made some design choices, but I hope this is enough to give you a general idea of how you can implement it.

Resources