[英]How to select the TOP 1 record per group (Partition)
我有一個名為tblRoutes的表,該表保存一個唯一的from和to路由列表(f = from; t = to):
| fCity | fState | tCity | tState |
|========|========|========|========|
|New York| NY | Miami | CA |
|Houston | TX |New York| NY |
...
然后,我有一個名為tblCarrierRates的表,該表列出了運營商提供的用於某些路線的一系列等級和價格:
| fCity | fState | tCity | tState | Tier | Rate | CarrID | CarrName |
|========|========|========|========|======|======|========|=============|
|New York| NY | Miami | CA | 2 | $2.99| ABCD | Abracadabra |
|New York| NY | Miami | CA | 1 | $3.00| BUMP | Bumpy Rides |
|Houston | TX |New York| NY | 2 | $4.00| SLOW |Slow Carriers|
|Houston | TX |New York| NY | 2 | $4.01| ABCD | Abracadabra |
...
對於tblRoutes中列出的每個唯一路由,我正在尋找tblCarrierRates提供的1個“最佳” 路由 。
對於“最好”的標准是最低級 ,其次是最低的 。
結果需要返回tblCarrierRates中顯示的所有字段,因此基於以上tblRoutes中顯示的2條路由 ,所需結果將是:
| fCity | fState | tCity | tState | Tier | Rate | CarrID | CarrName |
|========|========|========|========|======|======|========|=============|
|New York| NY | Miami | CA | 1 | $3.00| BUMP | Bumpy Rides |
|Houston | TX |New York| NY | 2 | $4.00| SLOW |Slow Carriers|
我正在研究的方法是按Tier升序排序,然后按Rate排序,然后對fCity,fState,tCity和tState的每個唯一組合如何匹配TOP 1記錄:
SELECT A.fCity, A.fState, A.tCity, A.tState, Q.Tier, Q.Rate, Q.CarrID, Q.CarrName
FROM tblRoutes As A LEFT JOIN
(SELECT TOP 1 B.CarrID, B.CarrName, B.fCity, B.fState, B.tCity, B.tState, B.Rate, B.Tier
FROM tblCarrierRates As B
ORDER BY tblCarrierRates.Tier ASC, tblCarrierRates.Rate ASC) As Q
ON (A.tState = Q.tState) AND (A.tCity = Q.tCity) AND (A.fState = Q.fState) AND (A.fCity = Q.fCity);
查詢不會失敗,但是您可能會猜到,我編寫的子查詢(Q)對於tblRoutes中的每個路由僅返回一條記錄,而不是1條記錄 ,因此最終結果是:
| fCity | fState | tCity | tState | Tier | Rate | CarrID | CarrName |
|========|========|========|========|======|======|========|=============|
|New York| NY | Miami | CA | 1 | $3.00| BUMP | Bumpy Rides |
|Houston | TX |New York| NY | | | | |
...如您所見,休斯頓到紐約沒有任何匹配項,因為我的子查詢僅返回1個結果,而不是每個路線返回1個結果。
我如何獲得想要的結果?
我相信你正在尋找的SQL Server和Oracle分析/窗口化功能,如的等效ROW_NUMBER() OVER (PARTITION .. ORDER BY)
例如, 像這樣 。
盡管這不是MS Access中直接提供的,但我相信可以通過應用相關子查詢來模擬MS Access中的行編號功能,該子查詢對具有相同“分區”(由聯接篩選器定義)的行數進行計數),並通過計算同一分區中“低於”排序條件的前一行的數量來對每一行進行排名:
SELECT A.fCity, A.fState, A.tCity, A.tState, Q.Tier, Q.Rate, Q.CarrID, Q.CarrName, TheRank
FROM tblRoutes As A LEFT JOIN
(
SELECT B.CarrID, B.CarrName, B.fCity, B.fState, B.tCity, B.tState, B.Rate, B.Tier,
(
SELECT COUNT(*) + 1
FROM tblCarrierRates rnk
-- Partition Simulation (JOIN)
WHERE B.fCity = rnk.fCity AND B.fState = rnk.fState
AND B.tCity = rnk.tCity AND B.tState = rnk.tState
-- ORDER BY Simulation
AND (rnk.Tier < B.Tier OR
(rnk.Tier = B.Tier AND rnk.Rate < B.Rate))) AS TheRank
FROM tblCarrierRates As B) As Q
ON (A.tState = Q.tState) AND (A.tCity = Q.tCity)
AND (A.fState = Q.fState) AND (A.fCity = Q.fCity)
-- Now, you just want the top rank in each partition.
WHERE TheRank = 1;
只是警告性能-將對每一行執行子查詢。 同樣,如果有關系,則將返回兩行。
+1將以行號1開始每個分區(因為該分區中的前一行將為零)
編輯,取出評論
SELECT A.fCity, A.fState, A.tCity, A.tState, Q.Tier, Q.Rate, Q.CarrID, Q.CarrName, TheRank
FROM tblRoutes As A LEFT JOIN
(
SELECT B.CarrID, B.CarrName, B.fCity, B.fState, B.tCity, B.tState, B.Rate, B.Tier,
(
SELECT COUNT(*) + 1
FROM tblCarrierRates rnk
WHERE B.fCity = rnk.fCity AND B.fState = rnk.fState
AND B.tCity = rnk.tCity AND B.tState = rnk.tState
AND (rnk.Tier < B.Tier OR
(rnk.Tier = B.Tier AND rnk.Rate < B.Rate))) AS TheRank
FROM tblCarrierRates As B) As Q
ON (A.tState = Q.tState) AND (A.tCity = Q.tCity)
AND (A.fState = Q.fState) AND (A.fCity = Q.fCity)
WHERE TheRank = 1
您的內部查詢需要按城市和州分組。 這將在每個城市州中產生1,從而允許外部聯接在這些字段上聯接。
獨立調試內部查詢,直到看到期望外部查詢工作的結果。 首先取出Top1,這樣您就可以看到排序和分組工作正常。 我會在您的內部查詢中明確添加ASC DESC,以便其他人知道您打算使頂部朝哪個方向工作。
您可以嘗試以下查詢:
SELECT fCity, fState, tCity, tState, MIN(Tier), MIN(Rate), CarrID, CarrName
FROM tblCarrierRates
GROUP BY fCity, fState, tCity, tState, CarrID, CarrName;
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.