SQL-查找没有匹配信用的发票

时间:2018-10-30 23:40:37

标签: sql-server

简化表如下:

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)当然不一定是连续的,只是一个简化的视图。

任何帮助将不胜感激。

3 个答案:

答案 0 :(得分:3)

这应该有效。我通过在信用额之前添加一些连续的发票进行测试。下面的查询显示所有具有匹配信用的发票,如果不存在匹配,则查询中别名“ 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

这是我使用的更新数据: data

这是我的结果:
enter image description here

答案 1 :(得分: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子句。这种情况将为您提供没有匹配项的尾随情况。

答案 2 :(得分:1)

我很久以前写过这篇文章,所以现在可能有更好的解决方法。另外,我还尝试将其调整为适合您的表结构,因此,如果没有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
)