我正在尝试返回由特定教师教授的所有中/高中课程。通过两个表的内部联接,可以正确显示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
答案 0 :(得分: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 :(得分:0)
这是因为您的所有empid
和grade
都是相同的。此连接多次匹配。
您在第一次加入时已经看到这一点,#Empl
中的行被重复三次(因为它与#MiddleCourses
中的所有3条记录相匹配)。
要减少这些,您需要使用更多的连接和/或使用不同的数据。尝试更改empid
和grade
,您希望看到我的意思。
答案 2 :(得分:0)
您可以使用ROW_NUMBER()
将middlecourses
与highcourses
匹配,具体取决于字母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
<强>输出:强>
empid grade MiddleCourse HighCourse
-------------------------------------------
1 5 English Calculus
1 5 Math CompSci
1 5 Science Physics
上述内容仅适用于middlecourses
和highcourses
的数量相等的情况。
如果middlecourses
和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
在highcourses
中再添加一条记录:
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
答案 3 :(得分: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
答案 4 :(得分: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