I have 4 tables like shown below
Table: leave_request
+------------+----------+--------------+------------+----------------------+
| request_id | staff_id | applied_from | applied_to | status |
+------------+----------+--------------+------------+----------------------+
| 1 | 10 | 01-07-2012 | 02-07-2012 | approved |
| 2 | 12 | 02-07-2012 | 02-07-2012 | awaiting HR approval |
+------------+----------+--------------+------------+----------------------+
Table: leave_approval
+-------------+-------------+---------------+-------------+
| request_id | approved_by | approved_from | approved_to |
+-------------+-------------+---------------+-------------+
| 1 | 1 | 01-07-2012 | 02-07-2012 |
| 1 | 2 | 01-07-2012 | 02-07-2012 |
| 2 | 1 | 02-07-2012 | 02-07-2012 |
+-------------+-------------+---------------+-------------+
Table: staff
+-----------+-------+----------+
| staff_id | name | group_id |
+-----------+-------+----------+
| 1 | jack | 1 |
| 2 | jill | 2 |
| 10 | sam | 3 |
| 12 | david | 3 |
+-----------+-------+----------+
Table: group
+-----------+------------+
| group_id | group_name |
+-----------+------------+
| 1 | admin |
| 2 | HR |
| 3 | staff |
+-----------+------------+
I need to make a report by joining these tables, It should look like below:
+----------+------------+----------+-------------+-----------+--------------+-----------+
|applied_by|applied_from|applied_to|approved_from|approved_to|approved_admin|approved_hr|
+----------+------------+----------+-------------+-----------+--------------+-----------+
| sam | 01-07-2012 |02-07-2012|01-07-2012 |02-07-2012 | Jack | Jill |
| david | 02-07-2012 |02-07-2012|02-07-2012 |02-07-2012 | Jack | null |
+----------+------------+----------+-------------+-----------+--------------+-----------+
Thanks in advance 🙂
Let’s take it step-by-step…
First, the entities you’re selecting are in the
leave_requesttable. So let’s start there:Now, you need to know the data for the
applied_bycolumn in the desired results. So you join thestafftable:(Note that I’m using aliases for the table names. This will come in handy later.)
Now you need to know
applied_fromandapplied_to, which you already have available:Now you need to know
approved_fromandapproved_to, which are in theleave_approvaltable:Uh oh, now we have a problem. There’s a one-to-many relationship, so now we have duplicated leave requests in the results. We need to filter that down somehow. You don’t specify how, so I’m going to make a couple assumptions: You want to know the
approved_fromandapproved_toof the “admin” approval AND there will only be ONE “admin” approval.Let’s reflect those assumptions in the table joins:
That should be better. Note that the table aliasing came in handy here because we now have two instances of the
stafftable for two different purposes in the same query. So we needed to distinguish them. (Keep in mind that I’m flying blind here and can’t actually test any of this. So correct me if there are any problems encountered along the way. I’m also free-handing this code because I don’t have MySQL handy, so let me know if there are syntax errors as well.)Now let’s add the
approved_adminfield to the results, which is already available:Finally, we need to know the
approved_hr. Andnullis allowed? We’re going to use a different join for this one, then. I’m also making similar assumptions to those above. Let’s try this:I’m not entirely sure about those latter
LEFT OUTER JOINs. The first one is definitely going to need to be a join that allows fornullvalues, but I’m not sure how the query engine handles joins beyond that. I’d prefer that they beINNER JOINs within the scope of the initialLEFT OUTER JOIN. But I guess all of that really also depends on the integrity of the data, which I can’t guarantee.It’s also worth noting that you claim to want
"Jack"as output when the value is"jack". I didn’t do any string manipulation in this code to make that happen. If the value should be capitalized in the data, then capitalize it in the data.Again, I can’t guarantee this code. But as a walk-through it should get you moving in the right direction. As I mentioned in a comment on the question, I really recommend picking up a book on MySQL if you’re going to be writing MySQL code.
Edit: One recommendation I can give is to the structure of the data itself. Specifically that
leave_approvaltable feels a bit messy, and it’s that table alone which is causing the confusion. I have a couple recommendations:approval_typeto theleave_approvaltable. At the very least this would indicate if it’s an admin approval, an HR approval, or any other kind of approval. (Are there even other kinds? Will there ever be?) Then you could also userequest_idandapproval_typeas a combined primary key, or at least a combined unique constraint, to enforce better data integrity and prevent duplicate approvals.leave_approvaltable. Have one set of columns foradmin_approval_*and one set forhr_approval_*. (Each set would include thestaff_idand relevant dates for the approval.) Thenrequest_iditself could be a primary key onleave_approvalmaking it one-to-one withleave_request. This would dramatically simplify the relational data, essentially turning aleave_approvalrecord into an optional set of additional information for aleave_requestrecord. The joins would become much simpler and the data would express itself much more clearly.