首页 文章

TSQL查询返回两次具有相同表的内部联接的行两次

提问于
浏览
9

我正在努力归还给定老师教授的所有中/高中课程 . 通过两个表的内部联接,可以正确显示3行 . 当我使用第3个表进行第二次内连接时,它返回6行而不是3行 .

不使用cte,DISTINCT,如何显示带有empid,中间类和高中类的3行?此外,两个外表都应该与主表连接 .

IF OBJECT_ID('tempdb..#empl') IS NOT NULL DROP TABLE #empl
IF OBJECT_ID('tempdb..#middlecourses') IS NOT NULL DROP TABLE #middlecourses
IF OBJECT_ID('tempdb..#highcourses') IS NOT NULL DROP TABLE #highcourses

create table #empl
(
    EmpId int,
    Grade int
)
insert into #empl select 1, 5   

create table #middlecourses
(
    EmpId int,
    Grade int,
    Course varchar(20)
)
insert into #middlecourses select 1, 5, 'Science'
insert into #middlecourses select 1, 5, 'Math'  
insert into #middlecourses select 1, 5, 'English'

create table #highcourses
(
    EmpId int,
    Grade int,
    Course varchar(20)
)
insert into #highcourses select 1, 5, 'Calculus'
insert into #highcourses select 1, 5, 'Physics' 
insert into #highcourses select 1, 5, 'CompSci'

select e.empid, e.grade, m.course as 'MiddleCourse'
from #empl e inner join #middlecourses m
on e.empid = m.empid 
and e.grade = m.grade

select e.empid, e.grade, m.course as 'MiddleCourse', h.course as 'HighCourse'
from #empl e inner join #middlecourses m
on e.empid = m.empid 
and e.grade = m.grade
inner join #highcourses h
on e.empid = h.empid
and e.grade = h.grade

drop table #empl
drop table #middlecourses
drop table #highcourses

5 回答

  • 1

    可能有一个更优雅的解决方案,但这应该适用于给出的场景:

    select e.empid, e.grade, c.course, c.CourseType
    from #empl e 
    inner join 
    (
    SELECT *, 'MiddleCourse' AS CourseType
    FROM #middlecourses m 
    UNION ALL
    SELECT *, 'HighCourse' AS CourseType
    FROM #highcourses h
    ) c ON c.EmpId = e.EmpId AND c.Grade = e.Grade
    
  • 0

    这是因为你的所有 empid 和_1231399都是一样的 . 此连接多次匹配 .

    您已经在第一次加入时看到了这一点, #Empl 中的行被重复三次(因为它匹配 #MiddleCourses 中的所有3条记录) .

    要减少这些,您需要使用更多的连接和/或使用不同的数据 . 尝试更改 empidgrade ,您希望看到我的意思 .

  • 0

    是的,edmondson是对的 . 您可以做的是一个带有ROW_NUMBER()的简单数据透视图,以使行唯一 .

    select
        *
    from
    (
        select e.empid, e.grade, 'MiddleCourses' as [Type] , m.course, ROW_NUMBER() OVER (ORDER BY e.EmpId) ClassNo
        from #empl e inner join #middlecourses m
        on e.empid = m.empid 
        and e.grade = m.grade
        union all
        select e.empid, e.grade, 'HighCourses' as [Type] ,m.course, ROW_NUMBER() OVER (ORDER BY e.EmpId) ClassNo
        from #empl e inner join #highcourses m
        on e.empid = m.empid 
        and e.grade = m.grade
    ) SourceTable
    pivot
    (
        MIN(Course)
        FOR [Type] IN (MiddleCourses,HighCourses)
    ) pivotTable
    
  • 0

    您可以使用 ROW_NUMBER()middlecourseshighcourses 匹配,具体取决于字母 course 排序:

    select e.empid, e.grade, m.course as 'MiddleCourse', h.course as 'HighCourse'
    from #empl e 
    cross apply (
       SELECT course, ROW_NUMBER() over (order by course) as rn
       FROM #middlecourses m
       WHERE e.empid = m.empid AND e.grade = m.grade ) m
    cross apply (
       SELECT course, ROW_NUMBER() over (order by course) as rn
       FROM #highcourses h
       WHERE e.empid = h.empid AND e.grade = h.grade ) h
    where m.rn = h.rn
    

    Output:

    empid   grade   MiddleCourse    HighCourse
    -------------------------------------------
    1       5       English         Calculus
    1       5       Math            CompSci
    1       5       Science         Physics
    

    以上内容仅适用于 middlecourseshighcourses 的数量相等的情况 .

    如果 middlecourseshighcourses 的数量不匹配,您可以使用上述查询的更复杂的变体:

    SELECT e.EmpId, e.Grade, t.MiddleCourse, t.HighCourse
    FROM #empl e
    INNER JOIN (
       SELECT COALESCE(m.empid, h.empid) AS empid, 
              COALESCE(m.grade, h.grade) AS grade,
              m.Course AS 'MiddleCourse', h.Course as 'HighCourse'
       FROM (SELECT empid, grade, course, 
                    ROW_NUMBER() over (partition by empid, grade 
                                       order by course) as rn
             FROM #middlecourses) m
       FULL JOIN (SELECT empid, grade, course, 
                         ROW_NUMBER() over (partition by empid, grade 
                                            order by course) as rn
                  FROM #highcourses) h 
       ON m.EmpId = h.EmpId AND m.Grade = h.Grade AND m.rn = h.rn ) t
    ON e.EmpId = t.empid AND e.Grade = t.grade
    

    highcourses 中还有一条记录:

    insert into #highcourses select 1, 5, 'Algebra'
    

    output is:

    EmpId   Grade   MiddleCourse    HighCourse
    -------------------------------------------
    1       5       English         Algebra
    1       5       Math            Calculus
    1       5       Science         CompSci
    1       5       NULL            Physics
    
  • 0

    首先,您需要了解内部联接的工作原理 . 内部联接将为您提供您要加入的两个表中的记录 .

    当您执行以下查询时,会出现您的问题

    select e.empid, e.grade, m.course as 'MiddleCourse'
    from #empl e inner join #middlecourses m
    on e.empid = m.empid 
    and e.grade = m.grade
    

    你会得到这个记录 .

    empid   grade   MiddleCourse
    1   5   Science
    1   5   Math
    1   5   English
    

    所以你得到了3条预期的记录,因为在#middlecourse表中有3条记录,其中empid = 1.所以内部联接就是这样的 . 它将从#empl表中一次选择一个empid并尝试在第二个表中找到此empiid的匹配行,即#middlecourses

    所以你有3条以上的查询记录 . 现在当你添加第二个内连接时,它会尝试从3个以上的记录中获取empid,并与第三个表#highcoures匹配 . 因此,对于每个empiid它将返回3记录 . 所以你将从第二个查询中获得 3*3 = 9 记录 .

    EmpId   Grade   EmpId   Grade   Course  EmpId   Grade   Course
    1        5      1       5       Science  1      5      Calculus
    1        5      1       5       Math     1      5      Calculus
    1        5      1       5       English  1      5      Calculus
    1        5      1       5       Science  1      5      Physics
    1        5      1       5       Math     1      5      Physics
    1        5      1       5       English  1      5      Physics
    1        5      1       5       Science  1      5      CompSci
    1        5      1       5       Math     1      5      CompSci
    1        5      1       5       English  1      5      CompSci
    

    这种情况的一个解决方案是在您的课程表上进行联合,然后使用#empl表进行内部联接 .

    select e.EmpId, e.Grade, a.Course from #empl e
    inner join (
    select * 
    from #middlecourses
    union
    select * from #highcourses) a on e.EmpId = a.EmpId
    

相关问题