有效地编写需要循环/加入未知次数的SQL查询

时间:2015-02-27 15:57:27

标签: sql sql-server sql-server-2008 reporting-services

我有一个像这样的表结构:

Order Table
OrderId int
OrderValue decimal

Payment Table
PaymentId int
OrderId int
PaymentAmount decimal
PaymentDate datetime

订单可以有很多付款。我需要找到哪个是按日期排序的第一笔付款,当添加到之前的付款时,大于或等于订单价值。

所以,如果我有以下内容:

| OrderId | OrderValue |
|       1 |       1000 |

| PaymentId | OrderId | PaymentAmount | PaymentDate |
|         1 |       1 |           100 | 2014-02-01  |
|         2 |       1 |           500 | 2014-02-02  |
|         3 |       1 |           400 | 2014-02-03  |
|         4 |       1 |           100 | 2014-02-04  |

在创建PaymentId 3时,OrderId 1已付清(OrderValue 1000 = 100 + 500 + 400)。

我可以想到3种做法;使用游标,多次自行加入支付表,或者只是将数据加载到应用程序中,然后通过代码以旧式方式查看。任何人都可以想到如何避免这些解决方案,甚至为什么我应该采用我所想到的解决方案之一?

这最终会在SSRS报告中结束(使用SQL Server 2008)

2 个答案:

答案 0 :(得分:2)

也许这会起作用

SELECT p.*
FROM Payment p JOIN Order o ON o.OrderId = p.OrderId
WHERE   (   SELECT SUM(p2.PaymentAmount)
            FROM Payment p2 ON p2.OrderId = o.OrderId 
            WHERE p2.PaymentDate <= p.PaymentDate 

        ) >= o.OrderValue 
AND p.PaymentDate = (   SELECT MIN(p3.PaymentDate)
                        FROM Payment p3 ON p.OrderId = o.OrderId 
                        WHERE ( SELECT SUM(p4.PaymentAmount)
                                FROM Payment p4 ON p4.OrderId = o.OrderId 
                                WHERE p4.PaymentDate <= p3.PaymentDate 
                           ) >= o.OrderValue
                   )

答案 1 :(得分:0)

如果你偏爱CTE以避免重复SUM逻辑,这对我有用:

WITH paidInFullPayments(PaymentId, OrderId, PaymentDate)
AS
(SELECT p.PaymentId, p.OrderId, p.PaymentDate
    FROM payment p
    INNER JOIN OrderTable o ON p.OrderId = o.OrderId
    WHERE (SELECT sum(p2.PaymentAmt) 
                FROM payment p2 
                WHERE p2.PaymentDate <= p.PaymentDate
                    AND p2.OrderId = p.OrderId) >= o.OrderValue
)
SELECT *
FROM paidInFullPayments
INNER JOIN OrderTable o ON paidInFullPayments.OrderId = o.OrderId
WHERE  paidInFullPayments.PaymentDate = (SELECT min(p3.PaymentDate) 
                                            FROM paidInFullPayments p3 
                                            WHERE p3.OrderId = o.OrderId)