2015-04-17 52 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