iT邦幫忙

0

如何 Left join 最符合的資料

我想要依照固定排序 Left join最相符的Appoinment

狀況是要列出 各user前/後一筆Appointment,且符合某些條件下必須優先顯示
因為是混合式條件,無法個別判斷後JOIN,故使用ORDER,再用DISTINCT+GROUP
例如: 該user有多筆時 status = 2 優先, status = 1, 再依時間...各種狀態 排序,但只需抓第一筆相符之後,再做Left JOIN

https://ithelp.ithome.com.tw/upload/images/20200526/20111199ABNR5MTFQq.png

而 DISTINCT+GROUP去抓第一筆的問題在 如何在GROUP後保持排序
用最佳解法做變化,可以有效達成效果

也希望有其他能直接拉出所需資料的方法

==================================================

因為每個Table都很大,所以我另外抓出Filter並排序,到這邊資料出來的狀況和排序都符合預期。
但想要抓出各資料的第一筆時,卻會變回系統排序的第一筆...

基本上order都index過...
希望版上大大可以提供一點建議>"<

主程式為下

SELECT User.*, NextAppointment.*, LastAppointment.*
								 
FROM( User )
LEFT JOIN(
	SELECT *, COUNT(DISTINCT( user_id ))
		FROM( SELECT Appointment.id, Appointment.user_id
              FROM( Appointment )
			  WHERE Appointment.from_time>='2020-05-26'
                AND Appointment.status=1
			  ORDER BY Appointment.from_time, Appointment.confirmed=1 DESC, Appointment.id DESC
			)NextAppointment_sub
						
		GROUP BY user_id 
	)NextAppointment	ON NextAppointment.user_id = User.id

LEFT JOIN(
	SELECT *, COUNT(DISTINCT( user_id ))
		FROM( SELECT Appointment.id, Appointment.user_id
              FROM( Appointment )
			  WHERE Appointment.from_time<='2020-05-26'
			  ORDER BY Appointment.status=2 DESC, Appointment.from_time DESC, Appointment.confirmed=1 DESC, Appointment.status=1 DESC, Appointment.id DESC
			)LastAppointment_sub
						
		GROUP BY user_id 
	)LastAppointment	ON LastAppointment.user_id = User.id AND LastAppointment.from_time >= User.FirstRequest
	

在Left join 的子查詢中...
抓取先前的Appointment,並以有狀態優先、時間... 等依序排列後,使用 DISTINCT +GROUP 抓取各user的第一筆符合資料,會變回系統排序


SELECT *, COUNT(DISTINCT( user_id ))
    FROM( SELECT Appointment.id, Appointment.user_id
          FROM( Appointment )
          WHERE Appointment.from_time<='2020-05-26'
          ORDER BY Appointment.status=2 DESC, Appointment.from_time DESC, Appointment.confirmed=1 DESC, Appointment.status=1 DESC, Appointment.id DESC
        )LastAppointment_sub

    GROUP BY user_id 

0
shing_pascal
iT邦新手 5 級 ‧ 2020-05-26 12:26:05
最佳解答

排序後的資料,前方新增一個序號欄位。
這樣就是你想要的資料順序。

犬千賀 iT邦新手 4 級 ‧ 2020-05-26 13:12:17 檢舉

謝謝!!! 我第一次用這種方式,雖然寫起來超醜的 XDD

2
浩瀚星空
iT邦超人 1 級 ‧ 2020-05-26 11:58:20

目前看不太出來你的問題點是什麼。
主要是你「但想要抓出各資料的第一筆時」這句話。
我不太明白你的問題重點。

可否在細說一下嘛?
因為就目前而言,看你的程式碼就是一個user對應2個left join過的東西。
你說的所謂各資料的第一筆指的是哪一個第一筆。這是我目前不懂的地方。

看更多先前的回應...收起先前的回應...
犬千賀 iT邦新手 4 級 ‧ 2020-05-26 12:06:59 檢舉

Left Join 的子查詢結果的,每user的第一筆

這樣我了解你的問題了。
其實我還在納悶你為何要用 DISTINCT
使用 DISTINCT 後會讓你原本排序好的資料再重新排序。
所以,你只能往不用 DISTINCT 的方式來達到你要的數據
基本上目前我不太明白
「COUNT(DISTINCT( user_id ))」
你打算拿他來做什麼。但理論上這樣子用。出來的結果理論上因該也是1吧?這基本上是給沒用子查尋時用的方法。
你都已經用了子查尋排序好了。也沒必要再用 DISTINCT 來破壞掉你排好的資料才對了。

犬千賀 iT邦新手 4 級 ‧ 2020-05-26 13:18:40 檢舉

會做這處理是因為Appointment表實在太大,且其實只需要排序下的第一筆相符資料,所以打算在Left join之前先做判斷+GROUP user處裡

確實這得要想一下。
我以前的做法是再多一次子查尋。
現在新的做法則是在架構上改變,不要再出現這樣的寫法。
畢竟資料大真的很傷腦筋。

其實如果你的table有說清楚及可能性的資料,還有對應的索引。
搞不好可以用另外的方式來處理。
但目前對你的資料情況不是很了解。所以也沒辦法很有效給你建議就是了。

犬千賀 iT邦新手 4 級 ‧ 2020-05-26 14:00:22 檢舉

主要狀況是要列出 各user前/後一筆Appointment,且符合某些條件下必須優先顯示
因為是混合式條件,無法個別判斷後JOIN,故使用ORDER
例如: 該user有多筆時 status = 2 優先, status = 1, 再依時間...各種狀態 排序

而 DISTINCT+GROUP去抓第一筆的問題在 如何在GROUP後保持排序
用最佳解法做變化可以有效達成此效果

0
twyes
iT邦新手 4 級 ‧ 2020-05-26 13:16:55

把Table 跟你要的描述清楚 , 沒辦法隔空抓藥

0
sam0407
iT邦高手 1 級 ‧ 2020-05-28 08:58:02

我很佩服大家寫SQL的功力,每次都能寫出讓我看半天都不一定看的懂的一長串SQL語法

我看了一下樓主寫的需求,其實也不難呀,我的作法會是:
1.先DISTINCT user_id並排序
2.再用cursor針對每個user_id作from_time,status,confirmed的判斷及排序,取每個user_id的Top 1

犬千賀 iT邦新手 4 級 ‧ 2020-05-28 09:35:24 檢舉

Cursor感覺能做得變化更多,改天會嘗試看看 謝謝你^^

之後是用group的特性下去做變化,其實query並沒有那麼長
因為不太會表達,所以發問才寫兩次LEFT JOIN表達 資料的條件排序

我要發表回答

立即登入回答