Question

I have three tables: attendance, cv_target, and candidate. I need to find the candidate count for a specific user.

I am not an expert in MySQL. I have tried the query below, but I'm unable to find the exact value.

SELECT
   attendance_date,
   cv_target_date_for,
   cv_requirement,
   job_id,
   cv_target,
   achi,
   recruiter_comment,
   recruiter_rating
FROM
   attendance f
RIGHT JOIN
   (
      SELECT
         cv_requirement,
         cv_target,
         cv_target_date_for,
         achi,
         recruiter_comment,
         recruiter_rating
      FROM
         cv_target a
      LEFT JOIN
         (
            SELECT
               COUNT(candidate_id) AS achi,
               cv_target_date,
               fk_job_id
            FROM
               candidate
            GROUP BY
               fk_job_id,
               cv_target_date
         ) b
            ON a.cv_requirement = b.fk_job_id
            AND a.cv_target_date_for = b.cv_target_date
      WHERE
         cv_target_date_for BETWEEN '2014-02-01' AND '2014-03-01'
         AND cv_recruiter = '36'
   ) c
      ON f.attendance_date=c.cv_target_date_for
GROUP BY
   cv_requirement,
   cv_target_date_for
ORDER BY
   c`.`cv_target_date_for` ASC

attendance

id   fk_user_id    attendance_date 
1    44            2014-02-24
2    44            2014-02-25
3    44            2014-02-26
4    44            2014-02-27
5    36            2014-02-24
6    44            2014-02-28

cv_target

id    cv_recruiter    cv_requirement    cv_target    cv_target_date_for
1     44              1                 3            2014-02-24
2     44              2                 2            2014-02-24
3     44              3                 2            2014-02-25
4     44              4                 3            2014-02-25
4     44              4                 3            2014-02-26

candidate

candidate_id    fk_posted_user_id    fk_job_id    cv_target_date
1               44                   1            2014-02-24
2               44                   3            2014-02-25
3               44                   3            2014-02-25
3               44                   4            2014-02-25
4               44                   4            2014-02-26
5               44                   5            2014-02-28
5               44                   5            2014-02-28

Desired result

attendance_date    cv_target_date_for    job_id    cv_target    achi(count)
2014-02-24         2014-02-24            1         3            1
2014-02-24         2014-02-24            2         2            null
2014-02-25         2014-02-25            3         2            2
2014-02-25         2014-02-25            4         3            1
2014-02-26         2014-02-26            4         3            1
2014-02-27         2014-02-27            null      null         null
2014-02-28         null                  5         null         2

Output that I am getting

attendance_date    cv_target_date_for    job_id    cv_target    achi(count)
2014-02-24         2014-02-24            1         3            1
2014-02-24         2014-02-24            2         2            null
2014-02-25         2014-02-25            3         2            2
2014-02-25         2014-02-25            4         3            1
2014-02-26         2014-02-26            4         3            1

Date 27 and 28 are not showing. I want those values also.

Was it helpful?

Solution

Original Answer

I think I understand what you want. The following assumes you want all attendance dates within a specific range for a specific user. And for each of those attendance dates, you want all cv_target records, if any. And for each of those, you want a count of the candidates.

Use a subquery to get the count. That's the only part that needs to go in the subquery. Only use a GROUP BY expression in the subquery, not the outer query. Only select the fields you need.

Use LEFT JOIN to get all the records from the table on the left side of the expression and only matching records from the table on the right side. So all records from attendance (that match the WHERE expression), and matching records from cv_target (regardless of whether they have a match in the candidate subquery), and then matching records from the candidate subquery.

Try this:

SELECT
   DATE_FORMAT(a.attendance_date, '%Y-%m-%d') AS attendance_date,
   DATE_FORMAT(t.cv_target_date_for, '%Y-%m-%d') AS cv_target_date_for,
   t.cv_requirement AS job_id,
   t.cv_target,
   c.achi AS `achi(count)`
FROM
   attendance AS a
LEFT JOIN
   cv_target AS t
      ON a.fk_user_id = t.cv_recruiter
      AND a.attendance_date = t.cv_target_date_for
LEFT JOIN
   (
      SELECT
         COUNT(candidate_id) AS achi,
         fk_job_id,
         cv_target_date
      FROM
         candidate
      WHERE
         fk_posted_user_id = 44
         AND cv_target_date BETWEEN '2014-02-01' AND '2014-03-01'
      GROUP BY
         fk_job_id,
         cv_target_date
   ) AS c
      ON t.cv_requirement = c.fk_job_id
      AND t.cv_target_date_for = c.cv_target_date
WHERE
   a.fk_user_id = 44
   AND a.attendance_date BETWEEN '2014-02-01' AND '2014-03-01'
ORDER BY
   ISNULL(t.cv_target_date_for), t.cv_target_date_for, t.cv_requirement

Note that the following line is not necessary for the correct result. However, depending on the database structure and amount of data, it may improve performance.

AND cv_target_date BETWEEN '2014-02-01' AND '2014-03-01'

The ISNULL function is being used to sort NULL to the bottom.

I've created an SQL Fiddle showing the output you request, except for cv_target_date_for. It's not possible to output values that do not exist in the data.


UPDATE

With the new data and new requirement of retrieving data where either cv_target or candidate has data for a particular attendance date, you need to add another table to get the job IDs. In your original question you had a table with ID numbers and job titles, but it had no dates.

You might want to rethink your database design. I'm not sure I understand how your tables relate to one another, but those two new records for the candidate table appear to be orphaned. All your joins are based on date, but you don't appear to have a table that links job ID numbers to dates.

You could create a derived table by doing a UNION of cv_target and candidate. Then use the derived table as the left side of the join.

Updated query:

SELECT
   DATE_FORMAT(a.attendance_date, '%Y-%m-%d') AS attendance_date,
   DATE_FORMAT(t.cv_target_date_for, '%Y-%m-%d') AS cv_target_date_for,
   j.job_id,
   t.cv_target,
   c.achi AS `achi(count)`
FROM
   attendance AS a
LEFT JOIN
   (
      SELECT
         cv_requirement AS job_id,
         cv_target_date_for AS job_date
      FROM
         cv_target
      WHERE 
         cv_recruiter = 44
         AND cv_target_date_for BETWEEN '2014-02-01' AND '2014-03-01'
      UNION
      SELECT
         fk_job_id AS job_id,
         cv_target_date AS job_date
      FROM
         candidate
      WHERE
         fk_posted_user_id = 44
         AND cv_target_date BETWEEN '2014-02-01' AND '2014-03-01'
   ) AS j
      ON a.attendance_date = j.job_date
LEFT JOIN
   cv_target AS t
      ON a.fk_user_id = t.cv_recruiter
      AND j.job_id = t.cv_requirement
      AND j.job_date = t.cv_target_date_for
LEFT JOIN
   (
      SELECT
         COUNT(candidate_id) AS achi,
         fk_job_id,
         cv_target_date
      FROM
         candidate
      WHERE
         fk_posted_user_id = 44
         AND cv_target_date BETWEEN '2014-02-01' AND '2014-03-01'
      GROUP BY
         fk_job_id,
         cv_target_date
   ) AS c
      ON j.job_id = c.fk_job_id
      AND j.job_date = c.cv_target_date
WHERE
   a.fk_user_id = 44
   AND a.attendance_date BETWEEN '2014-02-01' AND '2014-03-01'
ORDER BY
   ISNULL(t.cv_target_date_for), t.cv_target_date_for, j.job_id

I've created an updated SQL Fiddle showing the output you request, except for cv_target_date_for. It's not possible to output values that do not exist in the data (i.e. 2014-02-27).

If that's a typo and you meant 2014-02-28, then you'll need to select the date from the derived table instead of the cv_target table. And you should probably change the column heading in the result because it's no longer the cv_target_date_for date.

To get the date from either cv_target or candidate, change this line:

DATE_FORMAT(t.cv_target_date_for, '%Y-%m-%d') AS cv_target_date_for,

to this:

DATE_FORMAT(j.job_date, '%Y-%m-%d') AS job_date,

And you may need to tweak the order by expression to suit your needs.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top