对于SQL Server中的循环 - 这是正确的逻辑吗?

时间:2012-06-11 16:44:43

标签: sql-server sql-server-2008 for-loop while-loop

我正在尝试获取事务数据并清理它以满足我的分析需求。如何将事务记录到数据库中有一些限制,我试图绕过这些限制。

当客户下订单超过1个产品时,交易数据库不会将多个产品链接在一起。每个产品都有一个唯一的销售ID,但无法将多个销售ID分组为一个订单。这是一个示例:

OrderID   MultOrderID   CustomerID  SalesDate   SalesTime   ProductID   ProductCost ShippingCost
6082346                 7661X0A     2012-06-12  959         105         99.99       7.95
6082347   5809812YY6Y   T891002     2012-06-12  1005        222         99.95       7.95
6082348   5809812YY6Z   T891002     2012-06-12  1005        273         22.95       1.00
6082349   5809812YY71   T891002     2012-06-12  1005        285         499.95      1.00
6082350   5809812YY72   T891002     2012-06-12  1005        172         49.95       1.00
6082351   5809812YY73   T891002     2012-06-12  1005        105         99.99       7.95
6082352   5809812YY74   X637251     2012-06-12  1010        285         499.95      7.95
6082353   5809812YY75   X637251     2012-06-12  1010        30          1024.99     1.00
6082354                 T512AT0     2012-06-12  1017        172         49.95       7.95

此交易系统的另一个限制是它不能将超过4种产品一起发货。如果客户订购了5种产品,4种产品一起发货(并收取1次运费),剩下的产品单独发货并收取另一笔运费(是的,整体业务希望重建整个遗留系统...... )。

我要确定的是每个订单的产品数量,以及总产品成本和运输成本。

如果查看MultOrderID的最后4个字符,您会看到它是连续的,YY6Y变为YY6Z,然后翻到YY71,YY72。逻辑是标准化的 - 我知道如果CustomerID,SalesDate和SalesTime相同,那么我可以将产品配对在一起。我不知道的是我能做到这一点。

我认为实现这一目标的方法是通过CustomerID,SalesDate和SalesTime打破订单。然后,我得到一个for-loop或类似的东西来循环遍历各个条目。然后,我查找MultOrderID的最后4个字符并说 - 如果1,2和3相同,并且第4个字符在前一个订单的第4个字符之后,则将它们组合在一起,最多4个订单。如果orderID是范围中的第5到第8个订单,那么那是第2批货物等等。

这可以在SQL Server完成吗?如果不是这样,我该怎么写呢?在这种情况下我应该使用for-loop吗?

编辑:这是我想要的输出。请记住,在第4个产品发货后,我需要重新开始订购(因此,6个产品分为2个出货[4个产品和2个产品],9个产品分为3个出货[4,4和1]。 / p>

PRODUCTSSHIPPED SALESDATE   SALESTIME   CUSTOMERID  PRODUCTCOST SHIPPINGCOST
4               6/12/12         1005    T891002     672.8       10.95
1               6/12/12         1005    T891002     99.99       7.95
2               6/12/12         1010    X637251     1524.94     8.95
1               6/12/12         1017    T512AT0     49.95       7.95
1               6/12/12         959     7661X0A     99.99       7.95

4 个答案:

答案 0 :(得分:2)

从这句话来看,似乎你想要这个:

  

我想确定的是每个产品的出货数量   订单,以及总产品成本和运输成本。

http://sqlfiddle.com/#!3/e0e71/30

所以我不确定你使用foreach循环是什么意思?

更新:

使用子查询和天花板功能

更新了小提琴

FYI SQL是:

SELECT
SalesDate,
SalesTime,
CustomerID,
SUM(ProductCost),
SUM(ShippingCost)
FROM 

(
SELECT
       SalesDate,
       SalesTime,
       CustomerID,
       ProductCost,
       ShippingCost,
       ROW_NUMBER() OVER (PARTITION BY salesdate, salestime, customerid ORDER BY CustomerID) as ProdNumber
FROM Orders
) as Summary
group by SalesDate, SalesTime, CustomerID, ceiling(ProdNumber / 4.0)

我使用ROW_NUMBER获取每个订单的产品运行计数,然后将其作为子查询,以便我可以进行分组。分组只使用了产品数除以4(作为float)并使用ceiling函数向上舍入到最近的int以将其分组为4

答案 1 :(得分:1)

这应该在NumOrders字段中为您提供该客户/日期/时间的订单数量。它使用我最喜欢的函数Row_Number:

SELECT [CUSTOMERID], [SALESDATE], [SALESTIME], MAX(NumOrders)
FROM (
    SELECT [CUSTOMERID], 
    [SALESDATE],
    [SALESTIME],
    ROW_NUMBER() OVER(PARTITION BY [CUSTOMERID], [SALESDATE], [SALESTIME] ORDER BY [CUSTOMERID]) AS NumOrders
) t1
GROUP BY [CUSTOMERID], [SALESDATE], [SALESTIME]

答案 2 :(得分:1)

我不认为你需要一个循环。通常它被认为是sql中的一种不好的做法,除非完全不可避免。您是否可以假设,如果用户在同一日期时间完成订单,则该订单属于同一逻辑订单(订单组)? 无论如何,整个问题可以使用SQL服务器partition and over clauses来解决。看那里的样本D,我认为它做的很接近你需要的东西。

修改
range范围只在sql 2012中可用,但是你仍然可以使用partioning和rownumber,然后通过在返回的rownumber上使用简单计算(ROWNUMBER / 4)按结果分组

答案 3 :(得分:0)

我不确定为什么需要一个循环..

Select count(*) as ProductsOnOrder, LEFT(CustomerID,4), as CID,
       SalesDate, SalesTime, sum(productCost), sum(ShippingCost)
FROM YOUR_TABLENAME
GROUP BY left(CustomerID,4), salesdate, salestime

您想要显示哪个订单号?民?马克斯?所有的em?什么?关于产品的同样问题,您想列出产品还是只计算产品?

Select count(*) as ProductsOnOrder, LEFT(CustomerID,4), as CID,
       SalesDate, SalesTime, sum(productCost), sum(ShippingCost),
       min(orderID), Max(orderID)
FROM YOUR_TABLENAME
GROUP BY left(CustomerID,4), salesdate, salestime

由于您知道orderID对订单中的每一行都是连续的,您可以返回最小值/最大值并减去这两行以获得计数。