2017-06-03 85 views
1

這是我創建了一個查詢的簡化版本給我我想要的(與所選cpnt_id所有stud_id的列表,是否有compl_dte與否的值,但只有當項目的UserInput僅限於1記錄。的Oracle SQL MAX()與組 - 重複值

select stud.*, lrnhist.* from 
(select s.stud_id, 
     i.cpnt_id 
from student s, item i 
where s.stud_id in [UserInput] 
     c.cpnt_id in [UserInput] 
) stud 
left outer join 
(select lh.stud_id, 
     lh.cpnt_id, 
     max(lh.compl_dte) compl_dte 
from learnhist lh 
where lh.cpnt_id in [UserInput] 
group by lh.stud_id, lh.cpnt_id 
) 
on stud.stud_id = lrnhist.stud_id 

當它在哪裏運行UserInput指定2個或更多的項目,它返回正確的行,但compl_dte的返回值始終是相同的stud_id的每個值(因爲我使用max(compl_dte))我只是不確定我需要做什麼來確保返回的compl_dte是stud_id/cpnt_id對的最大值,而不是最大值對於stud_id,無論cpnt_id。

表值:

student 
stud_id 
1 
2 
3 
4 
item 
cpnt_id 
a 
b 
c 
d 
learnhist 
stud_id cpnt_id compl_dte 
1 a 5/5/2017 
1 a 3/3/2016 
1 b 10/10/2016 
2 c 8/8/2016 
3 b 2/2/2017 

結果,其中UserInput被stud_id = *和cpnt_id =一個:

stud_id cpnt_id compl_dte 
1 a 5/5/2017 
2 a 
3 a 
4 a 

這是正確的。 結果,其中UserInput是stud_id = *和cpnt_id = a和b:

stud_id cpnt_id compl_dte 
1 a 5/5/2017 
1 b 5/5/2017 
2 a 
2 b 
3 a 2/2/2017 
3 b 2/2/2017 
4 a 
4 b 

這是不是我要找的。結果我正在尋找在這種情況下:

stud_id cpnt_id compl_dte 
1 a 5/5/2017 
1 b 10/10/2016 
2 a 
2 b 
3 a 
3 b 2/2/2017 
4 a 
4 b 

首先發布在這裏,希望這一切都有道理,我問過在正確的地方!

+0

如果查詢需要多次連接,那麼最好有sql小提琴來幫助您測試我們的想法。嘗試在項目中使用交叉連接,並與關鍵學生ID和cpnt ID一起使用左連接。 –

回答

0

我相信問題可能是缺少加入STUDLRNHIST內嵌視圖之間謂語。
在你提供的查詢時,STUD聯視圖是STUDENTITEM之間的笛卡爾乘積,然後將其外部連接到LRNHIST認爲確實具有每STUD_ID/CPNT_ID對一個CMPL_DTE。但由於OUTER JOIN僅在STUD_ID謂詞上,您還會在STUD.CPNT_ID <> LRNHST.CPNT_ID的位置獲得匹配,提供額外的行。

你打破它,並期待在單獨的行內觀點:

對於STUD查詢:

SELECT STUDENT.STUD_ID, ITEM.CPNT_ID FROM STUDENT 
CROSS JOIN ITEM 
WHERE STUDENT.STUD_ID IN (1,2,3,4) 
AND ITEM.CPNT_ID IN ('a','b','c','d'); 

結果:

stud_id  cpnt_id 
1 a 
1 b 
1 c 
1 d 
2 a 
2 b 
2 c 
2 d 
... etc 

所以我們希望所有這些行的最終查詢。

如果你看看LRNHST獨立:

SELECT LEARNHIST.STUD_ID, 
       LEARNHIST.CPNT_ID, 
       MAX(LEARNHIST.COMPL_DTE) COMPL_DTE 
       FROM LEARNHIST 
       GROUP BY LEARNHIST.STUD_ID, LEARNHIST.CPNT_ID; 

確實是有每stud_id-cpnt_id對只有一排(存在於learnhist):

stud_id  cpnt_id  compl_dte 
1 b October, 10 2016 00:00:00 
1 a May, 05 2017 00:00:00 
3 b February, 02 2017 00:00:00 
2 c August, 08 2016 00:00:00 

現在,如果你加入只使用STUD_ID ,你會得到一個May 5th一行其中STUD1 - aLRNHST1 - a,但你也將獲得一排,其中LRNHST1 -b,因爲CPNT_ID上沒有連接謂詞。如果選擇全部五列,你可以看到複製進來:

SELECT STUD.*, LRNHIST.* FROM (
SELECT STUDENT.STUD_ID, ITEM.CPNT_ID FROM STUDENT 
CROSS JOIN ITEM 
WHERE STUDENT.STUD_ID IN (1,2,3,4) 
AND ITEM.CPNT_ID IN ('a','b','c','d')) STUD 
LEFT OUTER JOIN (SELECT LEARNHIST.STUD_ID, 
       LEARNHIST.CPNT_ID, 
       MAX(LEARNHIST.COMPL_DTE) COMPL_DTE 
       FROM LEARNHIST 
       GROUP BY LEARNHIST.STUD_ID, LEARNHIST.CPNT_ID 
       ) LRNHIST 
ON STUD.STUD_ID = LRNHIST.STUD_ID 
ORDER BY 1 ASC, 2 ASC, 3 ASC, 4 ASC, 5 ASC; 

結果:

s_stud s_cpnt l_stud l_cpnt l_compl 

1 a 1 a May, 05 2017 00:00:00 
1 a 1 b October, 10 2016 00:00:00 
1 b 1 a May, 05 2017 00:00:00 
1 b 1 b October, 10 2016 00:00:00 
1 c 1 a May, 05 2017 00:00:00 
1 c 1 b October, 10 2016 00:00:00 
1 d 1 a May, 05 2017 00:00:00 
1 d 1 b October, 10 2016 00:00:00 
2 a 2 c August, 08 2016 00:00:00 
... etc 

因爲這只是加入上stud_id,無論是OctMay記錄可以自由搭配STUD1-a匹配LRNHST1在其1-a對地表和1-b組兩者。現在

如果你CPNT_ID加入爲好,只有LRNHST記錄符合兩個CPNT_IDSTUD_ID將被退回。 (May1-aOct1-b

SELECT STUD.STUD_ID, STUD.CPNT_ID, LRNHIST.COMPL_DTE FROM (
SELECT STUDENT.STUD_ID, ITEM.CPNT_ID FROM STUDENT 
CROSS JOIN ITEM 
WHERE STUDENT.STUD_ID IN (1,2,3,4) 
AND ITEM.CPNT_ID IN ('a','b','c','d')) STUD 
LEFT OUTER JOIN (SELECT LEARNHIST.STUD_ID, 
       LEARNHIST.CPNT_ID, 
       MAX(LEARNHIST.COMPL_DTE) COMPL_DTE 
       FROM LEARNHIST 
       GROUP BY LEARNHIST.STUD_ID, LEARNHIST.CPNT_ID 
       ) LRNHIST 
ON STUD.STUD_ID = LRNHIST.STUD_ID 
AND STUD.CPNT_ID = LRNHIST.CPNT_ID 
ORDER BY 1 ASC, 2 ASC; 

結果:

stud_id  cpnt_id  compl_dte 
1 a May, 05 2017 00:00:00 
1 b October, 10 2016 00:00:00 
1 c (null) 
1 d (null) 
2 a (null) 
2 b (null) 
2 c August, 08 2016 00:00:00 
2 d (null) 
... etc 

現在你應該有每STUD_IDCPNT_ID對只有一排,用null對compl_dte在沒有LRNHST記錄匹配。

+0

太棒了,非常感謝所有的細節!這就是訣竅,它看起來像預期的那樣出來了。 –

0

使用因式分解的子查詢。

WITH all_ids AS (
SELECT s.stud_id as stud_id, 
     i.cpnt_id as cpnt_id 
    FROM student s 
CROSS JOIN item i) 
SELECT stud_id, cpnt_id, max(lh.compl_dte) as compl_dte 
    FROM all_ids 
LEFT JOIN learnhist lh USING (stud_id, cpnt_id) 
WHERE cpnt_id IN ('a', 'b') 
GROUP BY stud_id, cpnt_id 
ORDER BY stud_id;