简体   繁体   中英

Data from one table is missing while joining multiple tables in MYSQL

I have 3 tables called gps_stdnt_subj_xref a,gps_st_mark_fa1_fa3 b,gps_st_sa_mark_master c . First table containing list of subjects and other two containing subjects,students and their marks. In the 3rd table i have some additional subjects than the 2nd table (lot of other common fields are available in the 2nd and 3rd tables). while I executing the below query, in the output i am only getting the details of common subjects (subject which available in both 2nd and 3rd table). I am not much familiar with MYSQL(in oracle usually we give (+) at the end of the field on which the additional values available, then it will fetch all data). I tried with LEFT Join to get the expected output. But its giving only the output of common subjects. Sharing the query, please guide.

SELECT a.gps_subject,
       b.gps_st_mrk_gtot,
       b.gps_st_mrk_grade,
       b.gps_st_uid,
       b.gps_st_name,
       c.gps_st_sa_mark
  FROM gps_stdnt_subj_xref a
       LEFT JOIN (gps_st_mark_fa1_fa3 b, gps_st_sa_mark_master c)
          ON (    a.gps_subject = b.gps_st_mrk_subj
              AND b.gps_st_class = a.gps_class
              AND a.gps_subject = c.gps_st_sa_subject
              AND b.gps_st_uid = c.gps_st_sa_id
              AND c.gps_st_sa_class = b.gps_st_class
              AND b.gps_st_dvn = c.gps_st_sa_dvn
              AND a.gps_class = c.gps_st_sa_class)
 WHERE     a.gps_subject_status = 'Y'
       AND b.gps_st_mrk_stat = 'Y'
       AND b.gps_st_class = 'Class_07'
       AND b.gps_st_dvn = '07-C'

Ok, everything has already been said:

  1. you should have used consistently LEFT JOIN for both tables
  2. don't apply WHERE conditions on LEFT JOINED table in the where condition: you would filter the resulting rows and get only the one with matching rows

That's my proposal about how the resulting query should look:

SELECT a.gps_subject,
       b.gps_st_mrk_gtot,
       b.gps_st_mrk_grade,
       b.gps_st_uid,
       b.gps_st_name,
       c.gps_st_sa_mark
  FROM gps_stdnt_subj_xref a
       LEFT JOIN ( select * from gps_st_mark_fa1_fa3
   Where gps_st_mrk_stat = 'Y'
       AND gps_st_class = 'Class_07'
       AND gps_st_dvn = '07-C'
) b
On a.gps_subject = b.gps_st_mrk_subj
              AND b.gps_st_class = a.gps_class

        LEFT JOIN gps_st_sa_mark_master c
          ON a.gps_subject = c.gps_st_sa_subject
              AND b.gps_st_uid = c.gps_st_sa_id
              AND c.gps_st_sa_class =b.gps_st_class
              AND b.gps_st_dvn = c.gps_st_sa_dvn
              AND a.gps_class = c.gps_st_sa_class
 WHERE     a.gps_subject_status = 'Y'

I've pushed the where conditions in a sub query and used twice the LEFT JOIN.

===========================================================

EDITED : ok, the OP has signaled lots of rows with repeated "gps_subject" and all the other fields null. These should be rows where the subject table doesn't find matches on the other tables. But why are they repeated? After looking again at the query, it seemes that the "subject" table contains also a "class" (gps_class) attribute, so the same subject is repeated in the various classes.

The original query had a filter on the "left joined" table (turning it back to a standard inner join) on a field that was matched with "class" field (gpt_st_class).

Assuming what the OP needed was to limit the result on the 'Class_07' class, I moved this filter to the subject table and created the resulting table.

SELECT a.gps_subject,
       b.gps_st_mrk_gtot,
       b.gps_st_mrk_grade,
       b.gps_st_uid,
       b.gps_st_name,
       c.gps_st_sa_mark
  FROM gps_stdnt_subj_xref a
       LEFT JOIN ( select * from gps_st_mark_fa1_fa3
                    Where gps_st_mrk_stat = 'Y'
                      AND gps_st_dvn = '07-C'
                 ) b
              On a.gps_subject = b.gps_st_mrk_subj
             AND b.gps_st_class = a.gps_class

       LEFT JOIN (select * from gps_st_sa_mark_master 
                   Where gps_st_sa_dvn = '07-C'     
                 ) c
              ON a.gps_subject = c.gps_st_sa_subject
             AND b.gps_st_uid = c.gps_st_sa_id
             AND a.gps_class = c.gps_st_sa_class
 WHERE a.gps_subject_status = 'Y'
   and a.gps_class='Class_07';

However there's a point that is not clear to me: the two "mark" tables are joined for "student_id". Basically it means that if we have again some link that makes it impossible to return data from a table without matching data from the other.

Unless we have a student table, or some info about one of those two mark tables to be "complete" (so that it could be INNER JOINED with subject table) the best I can think of is:

SELECT a.gps_subject,
       b.gps_st_mrk_gtot,
       b.gps_st_mrk_grade,
       subj_class_stud.gps_st_uid,
       b.gps_st_name,
       c.gps_st_sa_mark
  FROM gps_stdnt_subj_xref a

       INNER JOIN (
         select gps_st_mrk_subj as subj, gps_st_uid as st_uid, gps_st_class st_class
           from gps_st_mark_fa1_fa3
          where gps_st_mrk_stat = 'Y'
            AND gps_st_dvn = '07-C'
          union all 
         select gps_st_sa_subject as subj, gps_st_sa_id as st_uid, gps_st_sa_class as st_class
           from gps_st_sa_mark_master 
          Where gps_st_sa_dvn = '07-C'  
       ) subj_class_stud
              on subj_class_stud.subj=a.gps_subject
             and subj_class_stud.st_class= a.gps_class

       LEFT JOIN ( select * from gps_st_mark_fa1_fa3
                    Where gps_st_mrk_stat = 'Y'
                      AND gps_st_dvn = '07-C'
                 ) b
              On subj_class_stud.subj = b.gps_st_mrk_subj
             AND b.gps_st_class = subj_class_stud.st_class
             and b.gps_st_uid = subj_class_stud.st_uid

       LEFT JOIN (select * from gps_st_sa_mark_master 
                   Where gps_st_sa_dvn = '07-C'     
                 ) c
              ON subj_class_stud.subj = c.gps_st_sa_subject
             AND subj_class_stud.st_uid = c.gps_st_sa_id
             AND subj_class_stud.st_class = c.gps_st_sa_class

 WHERE a.gps_subject_status = 'Y'
   and a.gps_class='Class_07';

Last point is that the OP will however have some null fields in the resultset when the "b" table is not matching (eg no subject). Probably the same fields are available on the "c" table but we don't have this information.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM