【问题标题】:How to fetch the non matching rows in Oracle如何在Oracle中获取不匹配的行
【发布时间】:2014-01-23 19:23:52
【问题描述】:

谁能帮我从 Oracle 的两个表中获取不匹配的行?

表:名称

Class_id        Stud_name
S001          JAMES
S001          PETER
S002          MARK

表:课程

 Course_id   Stud_name
  S001       JAMES
  S001       KEITH
  S002       MARK

输出

我需要将行显示为

   CLASS ID    STUD_NAME_FROM_NAME_TABLE    STUD_NAME_FROM_COURSE_TABLE
   --------------------------------------------------------------------- 
    S001          PETER                        KEITH

我使用 Oracle 连接来获取不匹配的名称:

      SELECT * 
        FROM Names, Course 
       WHERE Names.Class_id=Course.Course_id 
         AND Names.Stud_name<>Course.Stud_name   

此查询返回重复行。

【问题讨论】:

  • stackoverflow.com/a/7971429/2806972 只需点击链接即可。你能得到答案吗
  • @Rams 如何确认 Peter 或 James 是 S001 名称表中正确的人?
  • 不清楚你想要什么。从数据模型开始。为什么有一个类和一个课程,都使用相同的 id?表格是否应该显示相同的数据并且您正在寻找差异?课堂上所有未参加相应课程的学生?以及所有不在相应班级的学生?而不仅仅是列出错误的学生,您想列出每个班级/课程 ID 的错误学生吗?是这样吗?
  • 如果返回重复行,请在您的查询中使用 distinct。

标签: sql oracle


【解决方案1】:

好吧,我不确定我是否正确理解您的要求。我认为您想要一个所有 ID 的列表,其中班级表和课程表中的学生列表不同。然后你想显示 id 和在课堂上但不在课程中的学生和在课程中但不在课堂上的学生。

为此,您将完全外部联接表。这为您提供了既在课堂上又在课程中的学生,在课堂上而不在课程中的学生,以及在课程中和不在课堂上的学生。过滤您的结果,其中 class_id 或 course_id 为空,然后让学生在课程或班级中丢失。最后按 id 分组并列出学生。

select coalesce(class.class_id, course.course_id) as id
  , listagg(class.stud_name, ',') within group (order by class.stud_name) as missing_in_course
  , listagg(course.stud_name, ',') within group (order by course.stud_name) as missing_in_class
from class 
full outer join course 
on (class.class_id = course.course_id and class.stud_name = course.stud_name)
where class.class_id is null or course.course_id is null
group by coalesce(class.class_id, course.course_id);

这是展示其工作原理的 SQL 小提琴:http://sqlfiddle.com/#!4/8aaaa/2

编辑:在 Oracle 9i 中没有 listagg。你可以改用非官方的函数 wm_concat:

select coalesce(class.class_id, course.course_id) as id
  , wm_concat(class.stud_name) as missing_in_course
  , wm_concat(course.stud_name) as missing_in_class
from class 
full outer join course 
on (class.class_id = course.course_id and class.stud_name = course.stud_name)
where class.class_id is null or course.course_id is null
group by coalesce(class.class_id, course.course_id);

【讨论】:

  • 您好,我正在使用 oracle 9i,您能提供一个解决方案吗,谢谢
  • 请在 ORacle 9i 中提供替代解决方案,谢谢
  • 在 Ora9i 中没有官方的字符串聚合功能。但是,您可以使用未记录的 wm_concat。 (否则你必须自己编写一个字符串聚合。)我已经编辑了我的答案。
  • 似乎 Wm Concat 在 Oracle 9i 中也不支持,是否有任何替代方案
  • 对不起,我不知道。那么请看这里:stackoverflow.com/questions/15425760/…
【解决方案2】:

希望对你有帮助

  with not_in_class as 
      (select a.*
         from Names a
        where not exists ( select 'x'
                         from course b
                        where b.Course_id = a.class_id 
                          and a.Stud_name = b.Stud_name)),
    not_in_course as 
      (select b.*
         from course b
        where not exists ( select 'x'
                         from Names a
                        where b.Course_id = a.class_id 
                          and a.Stud_name = b.Stud_name))
    select x.class_id, 
           x.Stud_name NOT_IN_CLASS, 
           y.stud_name  NOT_IN_COURSE
      from not_in_class x, not_in_course y
     where x.class_id = y.course_id

输出

| CLASS_ID | NOT_IN_CLASS | NOT_IN_COURSE |
|----------|--------------|---------------|
|     S001 |        PETER |         KEITH |

唯一的问题是,如果给定 id 的两个表中都存在多个不匹配,则它适用于特定 id 的单个不匹配。如果同一个 id 有多个不匹配,则需要返工。

【讨论】:

  • 您好,上面的查询显示错误,给出的错误,不知道哪里出错了
  • 对不起,我错过了 WITH 子句:-P 再次更新了查询。
【解决方案3】:

Names 表中获取不匹配的行

 SELECT * FROM Names
 WHERE 
 NOT EXISTS
 (SELECT 'x' from Course 
  WHERE 
  Names.Class_id = Course.Course_id AND 
  Names.Stud_name = Course.Stud_name)

NamesCourse 中也获取不匹配的行!

 SELECT Names.Class_id,Names.Stud_name,C1.Stud_name
 FROM Names , Course C1
 WHERE Names.Class_id = C1.Course_id AND
 NOT EXISTS
 (SELECT 'x' from Course C2
  WHERE 
  Names.Class_id = C2.Course_id AND 
  Names.Stud_name = C2.Stud_name);

【讨论】:

  • 嗨,上面的查询返回了重复的行,它没有按照我的要求给出确切的结果
【解决方案4】:

如果你坚持加入你可以使用这个:

SELECT * 
FROM Names
   FULL OUTER JOIN Course ON Names.Class_id=Course.Course_id 
      AND Names.Stud_name = Course.Stud_name
WHERE Names.Stud_name IS NULL or Course.Stud_name IS NULL

【讨论】:

    【解决方案5】:

    当您要求不匹配的行时,我假设您想要names 中存在但course 中不存在的行。

    如果是这种情况,你可能会喜欢

    select * from names 
     where (class_id, stud_name ) not in 
       (select course_id, stud_name from course);
    

    您的查询返回了重复的行,因为 names 中的 每个 行它选择了 course 中满足 where 条件的 所有 行。

    因此,对于 names 中的 S001, PETER 行,S001, JAMES S001, KEITH 匹配该条件,因此,该行被“返回”了两次。

    编辑由于不清楚 stud_name 是主键还是唯一的(第二眼我认为不是),你可能想要一个

    select * from names 
     where not exists (
       select 1 from course where
          names.class_id  =  course.course_id and
          names.stud_name <> course.stud_name
     )
    

    Edit II如果您坚持使用join(根据您的评论),您可能想尝试一下

    select distinct names.* from...
    

    【讨论】:

    • 谢谢,我正在尝试使用联接而不是这个,是否可以实现任何联接技术而不是 IN 运算符
    • 我的输出应该是这样的
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-01-30
    • 2020-12-05
    • 2015-10-04
    • 2015-07-08
    • 2016-12-04
    • 2011-10-14
    相关资源
    最近更新 更多