I have to manage a gantt like interface where we can have multiple project (project_id). And need to get the minimum time to accomplish a project
My tables are the following :
Task
+---------+-------+----------------+
| id_task | name | days_allocated |
+---------+-------+----------------+
| 1 | task1 | 2 |
| 2 | task2 | 3 |
| 3 | task3 | 0.5 |
| 4 | task4 | 4 |
+---------+-------+----------------+
Task_predecessor (both field are linked to Task.id_task)
+------+-------------+
| task | predecessor |
+------+-------------+
| 2 | 1 |
| 3 | 1 |
| 4 | 2 |
| 4 | 3 |
+------+-------------+
Progress
+-------------+---------+------------+---------+
| id_progress | task_id | project_id | current |
+-------------+---------+------------+---------+
| 1 | 1 | 1 | 0 |
| 2 | 2 | 1 | 1 |
| 3 | 3 | 1 | 1 |
| 4 | 4 | 1 | 1 |
| 5 | 1 | 2 | 0 |
| 6 | 2 | 2 | 0 |
+-------------+---------+------------+---------+
So the Task table is our "template" and we track the advancment in the Progress table.
In this case, for project_id = 1, the id_task 1 is already done (progress.current is 0 where project_id = 1 AND task_id = 1)
So it's either tasks id_task 2 + id_task 4 or id_task 3 + id_task 4.
id_task 2 take more time than id_task 3 so the critical path is id_task 2 --> id_task 4 , 7 days
I have 2 options :
Option n°1
I can add a minimal_days column in my Task table because I know the predecessors. So the table will be
+---------+-------+----------------+--------------+
| id_task | name | days_allocated | minimal_days |
+---------+-------+----------------+--------------+
| 1 | task1 | 2 | 9 |
| 2 | task2 | 3 | 7 |
| 3 | task3 | 0.5 | 4.5 |
| 4 | task4 | 4 | 4 |
+---------+-------+----------------+--------------+
And I can retrieve the minimal days with this kind of query :
SELECT MAX(minimal_days) FROM progress
LEFT JOIN task ON task.id_task = progress.task_id
WHERE project_id = 1 AND current = 1
Option n°2
I rewrite the logic in a MySQL query ? But honestly, I dont know how ...
Option n°1 can be easily implemented, the result will be nearly instantaneous but the system is pretty limited, if a task is added or removed, all days_allocated must be recalculed and updated.
Option n°2 is in my opinion most difficult to write in MySQL. The request may be slower. Especially if we have to retrieve it for several projects at once. Once agin is a suposition... But the system will be more modular.
I prefear the option n°2, what about you ? Should I prefear another option ? Is there any other way to proceed ? Can you help me to write this logic in MySQL ?
PS : We can work with a total of 50 - 100 project at a time. A project can have 30 tasks max and the task_predecessor thing is pretty linear. We don't have very complex schema. So I think the result can be displayed in "real-time"
Related
I've got a procedural question that is likely going to expose how burnt out I am. I have 3 tables, users, projects and project_users. projects is joined with project_user to allow users to share projects.
I'd like to let, say, Bob see all of his projects and who he is sharing them with. In the example below Bob's sharing his 1 project with everyone. In his dashboard I'd like to show him "Bob's 1 Project" with everyone it's shared with. This is being managed in a while loop because Bob really has dozens of projects he's sharing with dozen's of people. The problem is, how can I show 1 project with everyone it's shared_with instead of showing the same project over and over each time there's a new shared_with value?
id | users | | id | projects | | id | owner_id | shared_with | project_id | role
---+-------------------- ---+------------------- ---+----------+-------------+------------+------
1 | bob#here.com | | 1 | Bob's 1 Project | | 1 | 1 | NULL | 1 | 1
2 | tom#there.com | | 2 | Tom's | | 2 | 1 | 4 | 1 | 2
3 | jan#red.com | | 3 | Jan's | | 3 | 1 | 2 | 1 | 2
4 | joe#somewhere.com | | 4 | Joe's Project | | 4 | 1 | 3 | 1 | 2
5 | fred#where.com | | 5 | Fred's Project | | 5 | 1 | 5 | 1 | 2
I have two MySQL tables called tasks and users. All I want to do is I don't want to display the tasks that is already done by a user in his panel. Suppose the task table has about 1000 entries and there are about 50000 users. Also the users and the tasks keep increasing.
One solution I can think of, 1st is creating a separate table of task x user size.
For example:
user table
+---------+--------+-------+
| user_id | fname | lname |
+---------+--------+-------+
| 1 | John | Smith |
| 2 | Steve | Mark |
+---------+--------+-------+
task table
+---------+-------------+---------------+
| task_id | task | task_duration |
+---------+-------------+---------------+
| 1 | Do task 1 | 1 hour |
| 2 | Do task 2 | 1 hour |
+---------+-------------+---------------+
Creating a separate table called display
+------------+---------+---------+
| display_id | task_id | user_id |
+------------+---------+---------+
| 1 | 1 | 1 |
| 2 | 1 | 2 |
| 3 | 2 | 1 |
| 4 | 2 | 2 |
+------------+---------+---------+
So only listed tasks will be shown to the particular user.
The problem is that This does not look like an efficient solution. How can I design table in this scenario in an efficient way. If not what are the other ways?
I wanted to make a learning apps with a completed questions progress track on each level. I have 2 tables which contain all the level with its question count, and a table that save an user progress (completed questions) on each level. Here is the record,
Level table:
+----------+----------------------+-------------+--------+
| id_level | name | jumlah_soal | id_sub |
+----------+----------------------+-------------+--------+
| 1 | Basic Level 1 | 5 | 1 |
| 2 | Basic Level 2 | 6 | 1 |
| 3 | Basic Level 3 | 7 | 1 |
| 8 | Intermediate Level 1 | 5 | 2 |
| 9 | Intermediate Level 2 | 5 | 2 |
| 10 | Intermediate Level 3 | 5 | 2 |
..........................................................
Progress Table:
+-----------------+---------+-------------+----------+
| id_progreslevel | id_user | completed | id_level |
+-----------------+---------+-------------+----------+
| 1 | 1 | 2 | 1 |
| 2 | 1 | 3 | 2 |
| 3 | 2 | 2 | 1 |
+-----------------+---------+-------------+----------+
and when I joined the tables with the following query
SELECT IFNULL(progreslevel.id_user, 1) as id_user,
-> level.*, IFNULL(progreslevel.completed, 0) as completedquestions
-> FROM level LEFT JOIN progreslevel
-> ON level.id_level = progreslevel.id_level
-> WHERE level.id_sub = 1
-> HAVING id_user = 1;
It queries what I wanted:
+---------+----------+---------------+-------------+--------+--------------------+
| id_user | id_level | name | jumlah_soal | id_sub | completed questions |
+---------+----------+---------------+-------------+--------+--------------------+
| 1 | 1 | Basic Level 1 | 5 | 1 | 2 |
| 1 | 2 | Basic Level 2 | 6 | 1 | 3 |
| 1 | 3 | Basic Level 3 | 7 | 1 | 0 |
+---------+----------+---------------+-------------+--------+--------------------+
BUT, when I tried to change to query a progress for user ID = 2, it became like this:
+---------+----------+---------------+-------------+--------+--------------------+
| id_user | id_level | name | jumlah_soal | id_sub | completed questions |
+---------+----------+---------------+-------------+--------+--------------------+
| 2 | 1 | Basic Level 1 | 5 | 1 | 2 |
| 2 | 3 | Basic Level 3 | 7 | 1 | 0 |
+---------+----------+---------------+-------------+--------+--------------------+
Yes, the Basic Level 2 is gone because user 2 hadn't done it yet but user 1 had.
This is where I'm stuck, I want to whichever user I choose, its always query all the level, even when the other user had done it. It should be like this:
+---------+----------+---------------+-------------+--------+--------------------+
| id_user | id_level | name | jumlah_soal | id_sub | completed questions |
+---------+----------+---------------+-------------+--------+--------------------+
| 2 | 1 | Basic Level 1 | 5 | 1 | 2 |
| 2 | 2 | Basic Level 2 | 6 | 1 | 0 |
| 2 | 3 | Basic Level 3 | 7 | 1 | 0 |
+---------+----------+---------------+-------------+--------+--------------------+
How do I achieve this?
Thanks in advance and Sorry if you got dizzy either at my explanation or database, I tried my best to translate it, so it's understandable
I'm not really sure that I understand the requirement, but I think you're after something like this...
SELECT l.*
, 2 id_user
, COALESCE(MAX(p.completed),0) completed_questions
FROM level l
LEFT
JOIN progress p
ON p.id_level = l.id_level
AND p.id_user = 2
WHERE l.id_sub = 1
GROUP
BY l.id_level;
I have following DB structure:
Table cars:
+----+-----------------------+
| id | few other columns.... |
+----+-----------------------+
| 1 | ... |
| 2 | ... |
| 3 | ... |
+----+-----------------------+
Table properties:
+----+-------+
| id | name |
+----+-------+
| 1 | title |
| 2 | type |
| 3 | brand |
| 4 | color |
+----+-------+
Table cars_properties:
+----+--------+-------------+------------+
| id | car_id | property_id | txt |
+----+--------+-------------+------------+
| 1 | 1 | 1 | Volvo V70 |
| 2 | 1 | 2 | personal |
| 3 | 1 | 3 | Volvo |
| 4 | 1 | 4 | white |
| 5 | 2 | 1 | Volvo VV |
| 6 | 2 | 2 | personal |
| 7 | 2 | 3 | Volvo |
| 8 | 2 | 4 | blue |
| 9 | 3 | 1 | Volvo XXL |
| 10 | 3 | 2 | truck |
| 11 | 3 | 3 | Volvo |
| 12 | 3 | 4 | white |
+----+--------+-------------+------------+
I would like to get all cars that have unique/duplicated values in one or many properties. Currently I'm using this SQL pattern to get duplicates for car type and brand:
SELECT cars.id FROM cars
LEFT JOIN cars_properties AS cp_0 ON cp_0.car_id = cars.id AND cp_0.property_id = 2 # => type
LEFT JOIN cars_properties AS cp_1 ON cp_1.car_id = cars.id AND cp_1.property_id = 3 # => brand
INNER JOIN (
SELECT cp_0.txt AS type_txt, cp_1.txt AS brand_txt FROM cars
LEFT JOIN cars_properties AS cp_0 ON cp_0.car_id = cars.id AND cp_0.property_id = 2
LEFT JOIN cars_properties AS cp_1 ON cp_1.car_id = cars.id AND cp_1.property_id = 3
GROUP BY cp_0.txt, cp_1.txt
HAVING COUNT(cars.id) > 1
) dupes ON cp_0.txt=dupes.type_txt AND cp_1.txt=dupes.brand_txt;
And expected result is:
+----+
| id |
+----+
| 1 |
| 2 |
+----+
Explanation: Both cars with id = 1 and 2 has type and brand that is present in more than one car (multiple times).
As for unique cars, I'm just altering: HAVING COUNT(cars.id) = 1 and I want to find all rows where the combination of properties is present only in one car (once).
It works fine, but it's extremely slow with more than 2 properties I want to check.
I cannot change the DB structure, and I'm not sure how to optimize the query, or if there are better ways of achieving this.
It feels like I would need to implement counter table, where each property id and value (txt) would also store corresponding number of occurrences in cars, and update this counter on every insert/update/delete... But I still hope there is some better SQL, that could help. Do you know some? Any advice greatly appreciated, thanks!
PS: I tried to create fiddle for it, but after I build schema I cannot run any SQL on it. To quickly setup DB with data, you can check SQL Fiddle
I have a Facility Booking System and I would like to create a CSV format report.
1. I want to count total booking records
2. I want to count how many user booked our facilities, based on that timeslot
3. I want to combine two queries into one as I need to put the result into the CSV
And here is the table structure:
fbid | memberid | fbdate | fbtimeslot | fname | fposition | fattendance
------------------------------------------------------------------------------
1 | C00001 | 2014-12-12 | 1 | computer | 1 | 1
2 | C00002 | 2014-12-12 | 1 | computer | 4 | 3
3 | C00003 | 2014-12-12 | 1 | computer | 6 | 1
4 | C00002 | 2014-12-12 | 1 | computer | 8 | 3
5 | C00004 | 2014-12-12 | 1 | computer | 4 | 0
6 | C00002 | 2014-12-12 | 1 | computer | 24 | 1
7 | C00001 | 2014-12-12 | 2 | computer | 1 | 0
8 | C00002 | 2014-12-12 | 3 | computer | 1 | 0
For task 1, I have found the solution:
(fattendance = 3 means the position has changed and I have to keep record but the CSV report doesn't this)
SELECT fbtimeslot, COUNT(*) FROM facilitybooking WHERE fname='computer' AND fattendance<>3 GROUP BY fbtimeslot
But for 2 and 3, I tried more than 20 different statements but I still couldn't get the result.
Well, hard tasks though.
I will be very appreciated if you can help me to solve this.
Extras: SQLFiddle Link: http://sqlfiddle.com/#!2/4800b8/3