2015-04-17 46 views
9

我试图返回由给定的老师教所有中等/高中课程。使用两个表的内连接,可以正确显示3行。当我做第二个内部连接与第三个表时,它返回6行而不是3.TSQL查询返回双行与内部联接两次

如果不使用cte,DISTINCT,如何显示3行empid,中间班级和高中班?另外,这两个外部表都应该与主表连接。

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 
+0

你的第二个查询返回9行')。你认为结果最终会成为什么?例如,科学应该如何与物理学相匹配,而不是CompSci? – TZHX

+0

结果应该是3行;像两个单独的内部连接加入到一个结果集中。 – rbhat

回答

0

这是因为所有的empidgrade的是相同的。这个连接匹配很多次。

您已在第一次加入时看到此信息,因此#Empl中的行将被重复三次(因为它与#MiddleCourses中的所有3个记录相匹配)。

要减少这些,您需要使用更加独特的连接和/或使用不同的数据。试着改变empidgrade,你会希望看到我的意思。

+0

谢谢,你是指使用更加独特的连接和/或使用不同的数据是什么意思?我无法过滤#Empl.EmpId或#Empl.Grade,因为我需要返回#Empl中的所有内容。 – rbhat

+0

这个连接匹配很多次,因为你的条件是真的(因为'emp'和'grade'都是相同的值')。为了更独一无二,你需要更多的信息,这样你可以通过教室减少等我会改变数字,所以你可以理解。 –

0

您可以使用ROW_NUMBER()匹配middlecourses与根据字母course排序highcourses

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 

输出:

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

以上只会在情况下工作有同等数量的middlecourseshighcourses

但如果是的middlecourses数量和highcourses您可以使用上面的查询比较复杂一点变化之间的不匹配:在highcourses

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 

凭借多一个纪录:

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

输出为:

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

是,埃德蒙森是正确的。 你可以做的是一个简单的支点与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 
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 
1

首先你需要了解内部联接的作品。内部连接 将为您提供您在 加入的两个表中都存在的记录。

来到你的问题,当你执行下面的查询

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条预计,因为有3条记录#middlecourse表EMPID = 1,所以内部联接是这样的工作。它将从#empl表中选择一个empid,并尝试在第二个表中找到该empiid的匹配行,即#middlecourses

因此,您有来自上述查询的3条记录。现在,当你添加第二个内部联接时,它将尝试从3记录中获得empid,并且将与#highcoures的第三个表相匹配。所以对于每个经营者来说它都会返回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表进行内联接。因为它加入了一组1(你`#empl`)上,在一组3('#middlecourses`),然后一组3个试(`#highcourses

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 
+0

我明白一个内部连接是如何工作的,并且我明白为什么它返回那么多行。你没有发表任何建议。怎么来的? – rbhat

+0

更新了@rbhatup的答案 – Mukund