[Solved] joins in MySQL for leave management in PHP and MySQL [closed]


Let’s take it step-by-step…

First, the entities you’re selecting are in the leave_request table. So let’s start there:

SELECT leave_request.* FROM leave_request

Now, you need to know the data for the applied_by column in the desired results. So you join the staff table:

SELECT
  applied_staff.name AS applied_by
FROM
  leave_request
  INNER JOIN staff AS applied_staff ON leave_request.staff_id = applied_staff.staff_id

(Note that I’m using aliases for the table names. This will come in handy later.)

Now you need to know applied_from and applied_to, which you already have available:

SELECT
  applied_staff.name AS applied_by,
  leave_request.applied_from,
  leave_request.applied_to
FROM
  leave_request
  INNER JOIN staff AS applied_staff ON leave_request.staff_id = applied_staff.staff_id

Now you need to know approved_from and approved_to, which are in the leave_approval table:

SELECT
  applied_staff.name AS applied_by,
  leave_request.applied_from,
  leave_request.applied_to,
  admin_approval.approved_from,
  admin_approval.approved_to
FROM
  leave_request
  INNER JOIN staff AS applied_staff ON leave_request.staff_id = applied_staff.staff_id
  INNER JOIN leave_approval AS admin_approval ON leave_request.request_id = admin_approval.request_id

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_from and approved_to of the “admin” approval AND there will only be ONE “admin” approval.

Let’s reflect those assumptions in the table joins:

SELECT
  applied_staff.name AS applied_by,
  leave_request.applied_from,
  leave_request.applied_to,
  admin_approval.approved_from,
  admin_approval.approved_to
FROM
  leave_request
  INNER JOIN staff AS applied_staff ON leave_request.staff_id = applied_staff.staff_id
  INNER JOIN leave_approval AS admin_approval ON leave_request.request_id = admin_approval.request_id
  INNER JOIN staff AS approved_staff ON admin_approval.approved_by = approved_staff.staff_id
  INNER JOIN group AS approved_staff_group on approved_staff.group_id = approved_staff_group.group_id
WHERE
  approved_staff_group.group_name="admin"

That should be better. Note that the table aliasing came in handy here because we now have two instances of the staff table 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_admin field to the results, which is already available:

SELECT
  applied_staff.name AS applied_by,
  leave_request.applied_from,
  leave_request.applied_to,
  admin_approval.approved_from,
  admin_approval.approved_to,
  approved_staff.name AS approved_admin
FROM
  leave_request
  INNER JOIN staff AS applied_staff ON leave_request.staff_id = applied_staff.staff_id
  INNER JOIN leave_approval AS admin_approval ON leave_request.request_id = admin_approval.request_id
  INNER JOIN staff AS approved_staff ON admin_approval.approved_by = approved_staff.staff_id
  INNER JOIN group AS approved_staff_group on approved_staff.group_id = approved_staff_group.group_id
WHERE
  approved_staff_group.group_name="admin"

Finally, we need to know the approved_hr. And null is 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:

SELECT
  applied_staff.name AS applied_by,
  leave_request.applied_from,
  leave_request.applied_to,
  admin_approval.approved_from,
  admin_approval.approved_to,
  approved_staff.name AS approved_admin,
  hr_staff.name AS approved_hr
FROM
  leave_request
  INNER JOIN staff AS applied_staff ON leave_request.staff_id = applied_staff.staff_id
  INNER JOIN leave_approval AS admin_approval ON leave_request.request_id = admin_approval.request_id
  INNER JOIN staff AS approved_staff ON admin_approval.approved_by = approved_staff.staff_id
  INNER JOIN group AS approved_staff_group on approved_staff.group_id = approved_staff_group.group_id
  LEFT OUTER JOIN leave_approval AS hr_approval ON leave_request.request_id = hr_approval.request_id
  LEFT OUTER JOIN staff AS hr_staff ON hr_approval.approved_by = hr_staff.staff_id
  LEFT OUTER JOIN group AS hr_staff_group ON hr_staff.group_id = hr_staff_group.group_id
WHERE
  approved_staff_group.group_name="admin"
  AND hr_staff_group.group_name="HR"

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 for null values, but I’m not sure how the query engine handles joins beyond that. I’d prefer that they be INNER JOINs within the scope of the initial LEFT 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_approval table feels a bit messy, and it’s that table alone which is causing the confusion. I have a couple recommendations:

  1. Add an approval_type to the leave_approval table. 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 use request_id and approval_type as a combined primary key, or at least a combined unique constraint, to enforce better data integrity and prevent duplicate approvals.
  2. If there are only two kinds of approvals and that’s probably not going to change, reflect them both in the leave_approval table. Have one set of columns for admin_approval_* and one set for hr_approval_*. (Each set would include the staff_id and relevant dates for the approval.) Then request_id itself could be a primary key on leave_approval making it one-to-one with leave_request. This would dramatically simplify the relational data, essentially turning a leave_approval record into an optional set of additional information for a leave_request record. The joins would become much simpler and the data would express itself much more clearly.

solved joins in MySQL for leave management in PHP and MySQL [closed]