在 MYSQL 中加入多个 table 时,一个 table 的数据丢失
Data from one table is missing while joining multiple tables in MYSQL
我有 3 个 table 叫 gps_stdnt_subj_xref a,gps_st_mark_fa1_fa3 b,gps_st_sa_mark_master c
。第一个 table 包含科目列表,另外两个包含科目、学生及其分数。在第 3 个 table 中,我比第 2 个 table 有一些额外的主题(许多其他公共字段在第 2 个和第 3 个 table 中可用)。当我执行以下查询时,在输出中我只获得了常见主题的详细信息(主题在第二和第三 table 中可用)。我对 MYSQL 不是很熟悉(在 oracle 中,通常我们在附加值可用的字段末尾给出 (+)
,然后它将获取所有数据)。我尝试使用 LEFT Join 来获得预期的输出。但它只给出普通主题的输出。分享查询,请指导。
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'
好了,都说完了:
- 你应该对两个 tables 使用一致的 LEFT JOIN
- 不要在 where 条件中对 LEFT JOINED table 应用 WHERE 条件:您将过滤结果行并仅获取具有匹配行的行
这是我对结果查询的外观的建议:
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'
我已经在子查询中推送了 where 条件并使用了两次 LEFT JOIN。
============================================= ==============
EDITED:好的,OP 已经用重复的 "gps_subject" 和所有其他字段表示了很多行为空。这些应该是主题 table 在其他 table 上找不到匹配项的行。但是为什么会重复呢?再次查看查询后,"subject" table 似乎还包含一个 "class" (gps_class) 属性,因此在各种 [=54] 中重复相同的主题=]es.
原始查询在与 "class" 字段匹配的字段上对 "left joined" table(将其转回标准内部联接)进行了筛选(gpt_st_class).
假设 OP 需要限制 'Class_07' class 上的结果,我将此过滤器移至主题 table 并创建了结果 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';
但是有一点我不清楚:两个 "mark" table 是为了 "student_id" 加入的。基本上这意味着,如果我们再次有一些 link,那么如果不匹配另一个 table 的数据,就不可能 return 数据。
除非我们有一个学生 table,或者关于这两个标记 table 之一的一些信息是 "complete"(这样它就可以与主题 table) 我能想到的最好的是:
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';
最后一点是,当 "b" table 不匹配(例如,没有主题)时,OP 在结果集中会有一些空字段。
"c" table 上可能有相同的字段,但我们没有此信息。
我有 3 个 table 叫 gps_stdnt_subj_xref a,gps_st_mark_fa1_fa3 b,gps_st_sa_mark_master c
。第一个 table 包含科目列表,另外两个包含科目、学生及其分数。在第 3 个 table 中,我比第 2 个 table 有一些额外的主题(许多其他公共字段在第 2 个和第 3 个 table 中可用)。当我执行以下查询时,在输出中我只获得了常见主题的详细信息(主题在第二和第三 table 中可用)。我对 MYSQL 不是很熟悉(在 oracle 中,通常我们在附加值可用的字段末尾给出 (+)
,然后它将获取所有数据)。我尝试使用 LEFT Join 来获得预期的输出。但它只给出普通主题的输出。分享查询,请指导。
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'
好了,都说完了:
- 你应该对两个 tables 使用一致的 LEFT JOIN
- 不要在 where 条件中对 LEFT JOINED table 应用 WHERE 条件:您将过滤结果行并仅获取具有匹配行的行
这是我对结果查询的外观的建议:
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'
我已经在子查询中推送了 where 条件并使用了两次 LEFT JOIN。
============================================= ==============
EDITED:好的,OP 已经用重复的 "gps_subject" 和所有其他字段表示了很多行为空。这些应该是主题 table 在其他 table 上找不到匹配项的行。但是为什么会重复呢?再次查看查询后,"subject" table 似乎还包含一个 "class" (gps_class) 属性,因此在各种 [=54] 中重复相同的主题=]es.
原始查询在与 "class" 字段匹配的字段上对 "left joined" table(将其转回标准内部联接)进行了筛选(gpt_st_class).
假设 OP 需要限制 'Class_07' class 上的结果,我将此过滤器移至主题 table 并创建了结果 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';
但是有一点我不清楚:两个 "mark" table 是为了 "student_id" 加入的。基本上这意味着,如果我们再次有一些 link,那么如果不匹配另一个 table 的数据,就不可能 return 数据。
除非我们有一个学生 table,或者关于这两个标记 table 之一的一些信息是 "complete"(这样它就可以与主题 table) 我能想到的最好的是:
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';
最后一点是,当 "b" table 不匹配(例如,没有主题)时,OP 在结果集中会有一些空字段。 "c" table 上可能有相同的字段,但我们没有此信息。