简化表看起来像这样:
BillID|ProductID|CustomerID|Price|TypeID
------+---------+----------+-----+-------
111111|Product1 |Customer1 | 100| I
111112|Product1 |Customer1 | -100| C
111113|Product1 |Customer1 | 100| I
111114|Product1 |Customer1 | -100| C
111115|Product1 |Customer1 | 100| I
我需要找到具有匹配信用(C)但没有匹配信用(最后一条记录)的“奇数”发票的发票(I) - 或者相反(没有相应信用的无法匹配的发票)。
到目前为止,我有这个:
SELECT Invoices.billid, Credits.billid
FROM
(SELECT B1.billid
FROM billing B1
WHERE B1.typeid='I') Invoices
INNER JOIN
(SELECT B2.billid
FROM billing B2
WHERE B2.typeid='C') Credits
ON Invoices.customerid = Credits.customerid
AND Invoices.productid = Credits.productid
AND Invoices.price = -(Credits.price)
但它显然不起作用,因为它返回的东西如下:
billid | billid2
-------+ -------
111111 | 111112
111113 | 111114
111115 | 111114
我想得到的是一份无与伦比的发票清单;
billid |
-------+
111115 |
或者只选择匹配的发票;
billid | billid2
-------+ -------
111111 | 111112
111113 | 111114
发票号码(BillID)当然不一定是连续的,它只是一个简化的视图。
任何帮助,将不胜感激。
我很久以前写过这个,所以现在可能有更好的方法来解决它。我也试图让它适应你的桌面结构,所以如果它不是100%那么道歉。我还假设您的BillID按日期顺序是顺序的,即稍后输入更大的数字。我还假设发票总是积极的,信用票据总是负面的 - 所以我不打扰检查类型。
本质上,查询过滤掉任何匹配的项目。
无论如何这里是:
select *
from billing X
/* If we are inside the number of unmatched entries then show it. e.g. if there are 3 unmatched entries, and we are in the top 3 then display */
where (
/* Number of later entries relating that match this account entry e.g. Price/Product/Customer */
select count(*)
from billing Z
where Z.Customer = X.Customer and Z.ProductID = X.ProductID
and Z.Price = X.Price
and Z.BillID >= X.BillId
) <=
(
/* Number of unmatched entries for this Price/Product/Customer there are, and whether they are negative or positive. */
select abs(Y.Number)
from (
-- Works out how many unmatched billing entries for this Price/Product/Customer there are, and whether they are negative or positive
select ProductID, CustomerID, abs(Price) Price, sum(case when Price < 0 then -1 else +1 end) Number
from billing
group by ProductID, CustomerID, abs(Price)
having sum(Price) <> 0
) as Y
where X.ProductID = Y.ProductID
and X.CustomerID = Y.CustomerID
and X.Price = case when Y.Number < 0 then -1*Y.Amount else Y.Amount end
)
这应该工作。我通过在信用卡之前添加几个连续发票进行测试。下面的查询显示所有具有匹配信用的发票,如果匹配不存在,则显示查询的别名“bar”部分的NULL。
SELECT * FROM (
SELECT
ROW_NUMBER() OVER(Partition By TypeID, CustomerID, ProductID, Price ORDER BY BillID ASC) AS rownumber,
*
FROM Billing
) AS foo
LEFT JOIN
(SELECT
ROW_NUMBER() OVER(Partition By TypeID, CustomerID, ProductID, Price ORDER BY BillID ASC) AS rownumber,
*
FROM Billing
) AS bar
on foo.CustomerID = bar.CustomerID and
foo.ProductID = bar.ProductID and
foo.rownumber = bar.rownumber and
foo.Price = -1*bar.Price
where foo.Price > 1
奇怪/偶数的事情让我有点担心。但假设这是一个增量键并且您的业务逻辑已到位,请尝试在WHERE子句,JOIN PREDICATE或实现Lead / Lag函数中包含此逻辑。
SELECT DISTINCT
Invoices.billid
,Credits.billid
FROM
(SELECT B1.billid
FROM billing B1
WHERE B1.typeid='I') Invoices
INNER JOIN (SELECT B2.billid
FROM billing B2
WHERE B2.typeid='C') Credits
ON Invoices.customerid = Credits.customerid
AND Invoices.productid = Credits.productid
AND Invoices.price = -(Credits.price)
AND (Invoices.Billid + 1) = Credits.Billid
注意:这是使用您的INNER JOIN,因此我们将获得发票具有相应信用的情况。您也可以执行FULL OUTER JOIN,然后包含指定WHERE Invoices.Billid IS NULL OR Credits.Billid IS NULL
的WHERE CLAUSE。这种情况会给你一个你没有匹配的尾随情况。