簡體   English   中英

如何選擇每個組的TOP 1記錄(分區)

[英]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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM