phpmyadmin 此内部连接sql查询有什么问题?

ugmeyewa  于 2022-11-09  发布在  PHP
关注(0)|答案(6)|浏览(117)

我想从数据库中导出一些数据。
基本上我想说的是:
1-从members表中选择mbr_name
2-选择存在于course_registration表中的值(基于mbr_id
3-将course_registration标识与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的实际数量是12 K,但是这个查询给了我120 K的结果,这显然是错误的!
那么,这里出了什么问题?我该如何解决这个问题?

更新:

以下是每个表的键:

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)
kqlmhetl

kqlmhetl1#

您遇到了所谓的基数问题。当一个表中的多行与另一个表中的一行匹配时,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 )
c2e8gylq

c2e8gylq2#

由于您只想选择成员名称,如果这能给出所需的结果,您可以尝试以下操作

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";
                 );
qlckcl4x

qlckcl4x3#

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

  • 会员可以注册一个或多个课程,
  • 每个课程可以有一个或多个注解。

如果是这种情况,由于冗余,你会得到更多的元组。在这种情况下,你只需要在你的第一个SELECT之后粘贴一个DISTINCT
此外,由于JOIN是sql中最耗费资源的操作,我将首先过滤数据,然后将join作为最后一个操作以提高效率。

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
pwuypxnk

pwuypxnk4#

我会先从注册开始,而不是从会员开始。通过得到一个注册课程的会员的DISTINCT列表,你就得到了一个较小的子集。从这个子集开始,加入那些被接受的会员的评论,你就得到了一个最终的列表。
一旦你有了这两个,加入回成员,以获得名称。我包括成员ID以及名称,因为如果你有两个或更多的“约翰”或“卡伦”的名字在注册。至少你有ID,以确认唯一的学生。

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
oipij1gg

oipij1gg5#

试试看:

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;
dced5bon

dced5bon6#

请尝试使用此选项,如果不起作用,请尝试对日期字段(crr_ts)使用“between”。

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

相关问题