如何选择每组TOP 1记录(分区)

时间:2015-05-15 10:32:53

标签: sql ms-access ms-access-2010 ms-access-2013

我有一张名为 tblRoutes 的表,其中包含一个来自路径的唯一列表(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 中列出的每条独特路线,我正在寻找1"最佳"来自 tblCarrierRates

"最好的标准"最低 Tier ,其次是最低费率

结果需要返回 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的每个唯一组合的TOP 1记录,tCity和tState:

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个。

我怎样才能达到我之后的结果?

3 个答案:

答案 0 :(得分:3)

我相信您正在寻找与ROW_NUMBER() OVER (PARTITION .. ORDER BY)类似的Sql Server和Oracle Analytic / Windowing函数,例如like so

虽然这不是在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 :(得分:0)

您的内部查询需要按城市和州分组。这将产生每个城市状态1,允许外部联接加入这些字段。

独立调试内部查询,直到您看到外部查询的结果。首先取出Top1,这样你就可以看到排序和分组工作正常。我会明确地将ASC DESC放在你的内部查询中,以便其他人知道你打算在哪个方向上工作。

答案 2 :(得分:0)

您可以尝试以下查询: -

SELECT fCity, fState, tCity, tState, MIN(Tier), MIN(Rate), CarrID, CarrName
FROM tblCarrierRates
GROUP BY fCity, fState, tCity, tState, CarrID, CarrName;