2011-11-28 224 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