这个内部联接sql查询有什么问题



我想从数据库导出一些数据。

基本上我想说的是:

1-从members表中选择mbr_name

2-选择course_registration表中存在的那些(基于mbr_id(

3-将course_registrationid与course_comments表连接

然后我还需要应用这些WHERE条件:

1-确保course_registration表中的crr_status设置为completed

2-确保course_registration表中的crr_ts"2021-03-07 00:00:00""2022-03-17 00:00:00"之间

3-确保course_comments表中的crm_confirmation设置为accept

所以我尽了最大的努力写下了这篇文章:

SELECT members.mbr_name
FROM members
INNER JOIN course_registration AS udt ON members.mbr_id = udt.crr_mbr_id 
INNER JOIN course_comments AS dot ON udt.crr_cor_id = dot.crm_reference_id
WHERE udt.crr_status = "completed" AND udt.crr_ts >= "2021-03-07 00:00:00" AND udt.crr_ts < "2022-03-17 00:00:00"
AND dot.crm_confirmation = "accept";

但这会以某种方式给出错误的数据。

具有所有这些条件的members的实际数量是12K,但这个查询给了我120K的结果,这显然是错误的!

那么这里出了什么问题?我该如何解决这个问题?


更新:

以下是每张表的密钥:

members (mbr_id (PK), mbr_name) 
course_registration (crr_id (PK), crr_mbr_id (FK), crr_cor_id (FK), crr_status)
course_comments (crm_id (PK), crm_reference_id (FK), crm_confirmation)

您有一个所谓的基数问题。当一个表上的多行与另一个表中的单行相匹配时,JOIN可能会导致结果集具有多行。您编写的JOIN将生成许多行:成员x课程x评论。JOIN就是这么做的。

看起来你只想在结果集中为每个。。。

  • 已完成一门或多门符合您标准的课程
  • 已提交一个或多个评论

所以让我们从一个子查询开始。它为提交了一个或多个符合您标准的课程的一个或更多评论的成员提供mbr_id值。

SELECT udt.crr_mbr_id
FROM course_registration udt
JOIN course_comments dot ON  udt.crr_cor_id = dot.crm_reference_id
WHERE udt.crr_status = "completed"
AND udt.crr_ts >= "2021-03-07 00:00:00"
AND udt.crr_ts < "2022-03-17 00:00:00"
AND dot.crm_confirmation = "accept"
GROUP BY udt.mbr_id

您可以使用该子查询的结果来查找您的成员。最后的查询是

SELECT members.mbr_name
FROM members
WHERE members.mbr_id IN (
SELECT udt.crr_mbr_id
FROM course_registration udt
JOIN course_comments dot ON  udt.crr_cor_id = dot.crm_reference_id
WHERE udt.crr_status = "completed"
AND udt.crr_ts >= "2021-03-07 00:00:00"
AND udt.crr_ts < "2022-03-17 00:00:00"
AND dot.crm_confirmation = "accept"
GROUP BY udt.mbr_id )

由于您只想选择会员名称,如果这会给出所需的结果,您可以按照以下方式进行尝试

select m.mbr_name
from Members m
where Exists ( select 1 from Course_Registration cr 
join Course_Comments cm on cr.crr_cor_id = cm.crm_reference_id
where cr.crr_mbr_id = m.mbr_id
And cr.crr_status = "completed" AND cr.crr_ts >= "2021-03-07 00:00:00" AND cr.crr_ts < "2022-03-17 00:00:00"
AND cr.crm_confirmation = "accept";
);

在不了解上下文的情况下,我的第一个猜测是:

  • 会员可以注册一个或多个课程
  • 每门课程都可以有一条或多条评论

如果是这种情况,由于冗余,您将获得更多的元组。在这种情况下,您只需要在第一次SELECT之后立即粘贴一个DISTINCT

此外,由于JOIN是sql中资源最昂贵的操作,为了提高效率,我会先过滤数据,然后将任何联接作为最后一个操作。类似这样的东西:

SELECT 
members.mbr_name 
FROM
(
SELECT DISTINCT
crm_reference_id
FROM 
course_comments
WHERE 
crm_confirmation = 'accept'
) accepted_comments
INNER JOIN 
(
SELECT DISTINCT
crr_mbr_id,
crr_cor_id
FROM 
course_registration
WHERE
crr_status = 'completed'
AND
crr_ts BETWEEN '2021-03-07 00:00:00' AND '2022-03-17 00:00:00'
) completed_courses 
ON 
accepted_comments.crm_reference_id = completed_courses.crr_cor_id
INNER JOIN 
members 
ON 
members.mbr_id = completed_courses.crr_mbr_id

我会先从注册开始,而不是从成员开始。通过获取注册课程的成员的DISTINCT列表,您可以获得较小的子集。同样,加入那些被接受的人的评论会给你一个最终的列表。

一旦你有了这两个,就加入到会员中来获得名字。我包括了会员ID和姓名,因为如果你有两个或多个";约翰;或";Karen"注册中的姓名。至少你有身份证来确认唯一的学生。

select
m.mbr_name,
m.mbr_id
from
( select distinct
cr.crr_mbr_id
from
course_registration cr
JOIN course_comments cc 
ON cr.crr_cor_id = cc.crm_reference_id
AND cc.crm_confirmation = 'accept'
WHERE 
cr.crr_status = 'completed'
AND cr.crr_ts >= '2021-03-07' 
AND cr.crr_ts < '2022-03-17' ) PQ
JOIN members m
ON PQ.crr_mbr_id = m.mbr_id 

尝试使用此选项,如果不起作用,则尝试使用"between"作为日期字段(crr_ts(。

select mbr.mbr_name from
(
select * from course_registration AS udt
INNER JOIN course_comments AS dot ON udt.crr_cor_id = dot.crm_reference_id
where dot.crm_confirmation = "accept" AND udt.crr_status = "completed" AND udt.crr_ts >= "2021-03-07 00:00:00" AND udt.crr_ts < "2022-03-17 00:00:00"
)x
INNER JOIN  members mbr on mbr.mbr_id = x.crr_mbr_id

试试这个:

SELECT *
FROM members M
INNER JOIN course_registration CR
ON CR.crr_mbr_id = M.mbr_id
AND CR.crr_status = 'completed'
AND CR.crr_ts BETWEEN '2021-03-07 00:00:00' AND '2022-03-17 00:00:00'
WHERE EXISTS(
SELECT * FROM course_comments CC
WHERE CC.crm_confirmation = 'accept'
AND CC.crm_reference_id = CR.crr_cor_id
)
ORDER BY M.mbr_id;

最新更新