2011-11-28 227 views
0

我一直在努力整個下午工作 - 這似乎很簡單,但我必須錯過一些東西!過濾SQL查詢返回的結果

我有一個查詢返回一些數據,它返回的兩列是「PackageWeight」和「PackageGroup」。從本質上講,我想過濾掉這些數據,以便每個「PackageGroup」只顯示一行 - 應該是「PackageWeight」列中值最高的那一行。

看起來很簡單,但我不能讓它在SQL Server中使用TOP 1和GROUP BY的組合工作。我肯定錯過了什麼!

SELECT VendorID, PackageID, PackageWeight, PackageGroup 
    FROM (SELECT VendorID, COUNT(*) AS qty 
      FROM VendorServices 
     GROUP BY VendorID 
     ) cs 
    JOIN (SELECT PackageServices.PackageID, lookupPackages.PackageWeight, lookupPackages.PackageGroup, COUNT(*) AS qty 
      FROM PackageServices 
      JOIN lookupPackages ON PackageServices.PackageID = lookupPackages.PackageID 
      GROUP BY PackageServices.PackageID, lookupPackages.PackageWeight, lookupPackages.PackageGroup 
     ) ps ON cs.qty >= ps.qty 
    WHERE (SELECT COUNT(*) 
      FROM VendorServices cs2 
      JOIN PackageServices ps2 ON cs2.ServiceTypeID = ps2.ServiceID 
     WHERE cs2.VendorID = cs.VendorID 
      AND ps2.PackageID = ps.PackageID 
     ) = ps.qty 

此查詢返回完整的數據集,我需要過濾。然而我的努力迄今未能:(

任何幫助非常讚賞

編輯 - 由於下面的貢獻者,到目前爲止,我有以下查詢:

with result_cte as 
(
SELECT VendorID, PackageID, PackageWeight, PackageGroup, 
    RANK() over (partition by PackageGroup order by PackageWeight desc) as [rank] 
FROM (SELECT VendorID, COUNT(*) AS qty 
    FROM VendorServices 
    GROUP BY VendorID 
    ) cs 
JOIN (SELECT PackageServices.PackageID, lookupPackages.PackageWeight, lookupPackages.PackageGroup, COUNT(*) AS qty 
    FROM PackageServices 
    JOIN lookupPackages ON PackageServices.PackageID = lookupPackages.PackageID 
    GROUP BY PackageServices.PackageID, lookupPackages.PackageWeight, lookupPackages.PackageGroup 
    ) ps ON cs.qty >= ps.qty 
WHERE (SELECT COUNT(*) 
    FROM VendorServices cs2 
    JOIN PackageServices ps2 ON cs2.ServiceTypeID = ps2.ServiceID 
    WHERE cs2.VendorID = cs.VendorID 
    AND ps2.PackageID = ps.PackageID 
    ) = ps.qty 
) 

select * 
from result_cte 
WHERE [rank] = 1 
ORDER BY VendorID 

到目前爲止,好,我仍然會看看@gbn提出的APPLY運算符,因爲這對我來說是新的 - 我仍然需要做一些測試來確保這個查詢在100%的時間內運行,但最初的跡象是好的!

感謝迄今爲止所做的貢獻。

編輯2 - 遺憾的是,在用更多示例數據填充數據庫後,此查詢失敗。它似乎錯過了一些條目。

也許我需要更多地解釋一下這裏發生了什麼。通過我的原始查詢返回的數據會列出系統中的每個客戶,以及派生的PackageID(由該查詢計算)以及在查找表中分配給該Package的權重和組。

我需要過濾原始結果表,這樣我才能從每個組中獲取不超過一個包,每個客戶(每個客戶可能有一個或多個組的包,但可能沒有每個組的包)

明天我會帶着更新的一面看,因爲我想我可能會在'看不到樹木的情況'!

謝謝大家。

+1

的可能重複[SQL服務器上 - 選擇TOP 5行每個FK(http://stackoverflow.com/questions/1450603/sql-server-select-top-5-rows -for-each-fk)或http://stackoverflow.com/q/1164483/27535。還有幾十個:http://stackoverflow.com/questions/tagged/greatest-n-per-group – gbn

+1

你使用的是什麼版本的SQL Server? – Lamak

+0

@Lamak - SQL Server 2008. – JimmE

回答

1

你可以試試嗎?如果在同一組中有多個具有相同權重的記錄,那麼這並非無懈可擊。還有其他方法來處理它。

with result_cte as 
(
SELECT VendorID, PackageID, PackageWeight, PackageGroup 
FROM (SELECT VendorID, COUNT(*) AS qty 
    FROM VendorServices 
    GROUP BY VendorID 
    ) cs 
JOIN (SELECT PackageServices.PackageID, lookupPackages.PackageWeight, lookupPackages.PackageGroup, COUNT(*) AS qty 
    FROM PackageServices 
    JOIN lookupPackages ON PackageServices.PackageID = lookupPackages.PackageID 
    GROUP BY PackageServices.PackageID, lookupPackages.PackageWeight, lookupPackages.PackageGroup 
    ) ps ON cs.qty >= ps.qty 
WHERE (SELECT COUNT(*) 
    FROM VendorServices cs2 
    JOIN PackageServices ps2 ON cs2.ServiceTypeID = ps2.ServiceID 
    WHERE cs2.VendorID = cs.VendorID 
    AND ps2.PackageID = ps.PackageID 
    ) = ps.qty 
) 

select * 
from result_cte 
where result_cte.PackageWeight = (select top 1 highestweight.PackageWeight from result_cte highestweight 
           where highestweight.PackageGroup = result_cte.PackageGroup 
           order by highestweight.PackageWeight desc) 

或者,你可以這樣做:

with result_cte as 
(
SELECT VendorID, PackageID, PackageWeight, PackageGroup, 
    ROW_NUMBER() over (partition by PackageGroup order by PackageWeight desc) as [row] 
FROM (SELECT VendorID, COUNT(*) AS qty 
    FROM VendorServices 
    GROUP BY VendorID 
    ) cs 
JOIN (SELECT PackageServices.PackageID, lookupPackages.PackageWeight, lookupPackages.PackageGroup, COUNT(*) AS qty 
    FROM PackageServices 
    JOIN lookupPackages ON PackageServices.PackageID = lookupPackages.PackageID 
    GROUP BY PackageServices.PackageID, lookupPackages.PackageWeight, lookupPackages.PackageGroup 
    ) ps ON cs.qty >= ps.qty 
WHERE (SELECT COUNT(*) 
    FROM VendorServices cs2 
    JOIN PackageServices ps2 ON cs2.ServiceTypeID = ps2.ServiceID 
    WHERE cs2.VendorID = cs.VendorID 
    AND ps2.PackageID = ps.PackageID 
    ) = ps.qty 
) 

select * 
from result_cte 
where [row] = 1 
+0

與基於ROW_NUMBER或APPLY的查詢進行比較,即使它有效,這也非常混亂 – gbn

+0

我並不是要解決作者的問題。我只是想展示不同的技術來獲得理想的結果。我提供的查詢需要驗證以獲得正確的結果。 –

+0

@ Eric.K.Yung - 非常感謝 - 我稍微修改了這個以使用RANK()而不是ROW_NUMBER(),因爲ROW_NUMBER()似乎沒有返回客戶沒有每個組的包的行。我將粘貼更新的查詢作爲對OP的編輯。 – JimmE

0

你願意接受一個任意的供應商和PackageID如果多個包有一組相同的最大重量?如果正常,只是把聚集在他們身上還有PackageWeight

SELECT max(VendorID), max(PackageID), max(PackageWeight), PackageGroup 
... 
GROUP BY PackageGroup 

否則,你需要做的E.Y.建議並執行嵌套查詢以首先查找每個組的最大權重並自行處理重複項(如果有)。

+0

謝天謝地,應用程序的性質使得包中的每個包都有獨特的權重。這實際上是加權/分組首先存在的原因 - 強制執行關於將軟件包分配給客戶的業務規則。 – JimmE

0

您可以使用MAX功能:

SELECT * FROM #one 
lbs groups 
5 0 
4 0 
1 0 
9 1 
2 1  

SELECT groups,MAX(lbs) 
FROM #one 
GROUP BY groups 

groups (No column name) 
0 5 
1 9 
0

由於後由Eric.K.Yung - 我終於解決了這個用了他的問題,但「通過分區」部分添加廠商ID(有效客戶ID)到的查詢。這確保了爲所有客戶返回包裹。

感謝所有人的貢獻。最終的查詢是:

with result_cte as 
(
SELECT VendorID, PackageID, PackageWeight, PackageGroup, 
    ROW_NUMBER() over (partition by PackageGroup, VendorID order by PackageWeight desc) as [row] 
FROM (SELECT VendorID, COUNT(*) AS qty 
    FROM VendorServices 
    GROUP BY VendorID 
    ) cs 
JOIN (SELECT PackageServices.PackageID, lookupPackages.PackageWeight, lookupPackages.PackageGroup, COUNT(*) AS qty 
    FROM PackageServices 
    JOIN lookupPackages ON PackageServices.PackageID = lookupPackages.PackageID 
    GROUP BY PackageServices.PackageID, lookupPackages.PackageWeight, lookupPackages.PackageGroup 
    ) ps ON cs.qty >= ps.qty 
WHERE (SELECT COUNT(*) 
    FROM VendorServices cs2 
    JOIN PackageServices ps2 ON cs2.ServiceTypeID = ps2.ServiceID 
    WHERE cs2.VendorID = cs.VendorID 
    AND ps2.PackageID = ps.PackageID 
    ) = ps.qty 
) 

select * 
from result_cte 
where [row] = 1 
+0

根據您的最終查詢與其基於的答案或實際上來自其他答案的差異,您可能會考慮將其添加到答案中。我的意思是,有人可能會發現它與本主題中發佈的任何其他正確解決方案一樣有用。 –

+0

@AndriyM - 當然 - 非常感謝。最終查詢添加到我的答案。 – JimmE