我有一个查询将导致在我们的SSRS 2008 R2服务器上创建客户账单.SQL Server实例也是2008 R2.查询很大,我不想出于安全原因发布整个事情等.
我需要对下面的示例数据做的是从结果集中删除带有73.19和-73.19的两行.因此,如果两行在LineBalance列中具有相同的绝对值且它们的总和为0并且如果它们在REF1列中具有相同的值,则应从结果集中删除它们.在结果集中仍应返回REF1 = 14598和行余额281.47的行,并且不应返回REF1 = 14598以下的其他两行.
其重点是"隐藏"会计错误及其对客户的更正.通过"隐藏"我的意思是,不要在他们收到的邮件中显示它.这里发生的事情是客户被错误地收费73.19,他们应该收到281.47的账单.所以,我们的AR部门.返回73.19到他们的帐户,并向他们收取正确数额281.47.如您所见,它们都具有相同的REF1值.

我会添加一个字段,其中包含显式标记,告诉您某个指控是错误/错误的反转,然后过滤掉这些行是微不足道的.即时执行可能会使您的报告变得相当缓慢.
但是,为了解决给定的问题,我们可以这样做.该解决方案假定这SysInvNum是唯一的.
DECLARE @T TABLE (SysInvNum int, REF1 int, LineBalance money);
INSERT INTO @T (SysInvNum, REF1, LineBalance) VALUES (3344299, 14602, 558.83);
INSERT INTO @T (SysInvNum, REF1, LineBalance) VALUES (3344298, 14598, 281.47);
INSERT INTO @T (SysInvNum, REF1, LineBalance) VALUES (3344297, 14602, -95.98);
INSERT INTO @T (SysInvNum, REF1, LineBalance) VALUES (3344296, 14598, -73.19);
INSERT INTO @T (SysInvNum, REF1, LineBalance) VALUES (3341758, 14598, 73.19);
INSERT INTO @T (SysInvNum, REF1, LineBalance) VALUES (11, 100, 50.00);
INSERT INTO @T (SysInvNum, REF1, LineBalance) VALUES (12, 100, -50.00);
INSERT INTO @T (SysInvNum, REF1, LineBalance) VALUES (13, 100, 50.00);
INSERT INTO @T (SysInvNum, REF1, LineBalance) VALUES (21, 200, -50.00);
INSERT INTO @T (SysInvNum, REF1, LineBalance) VALUES (22, 200, -50.00);
INSERT INTO @T (SysInvNum, REF1, LineBalance) VALUES (23, 200, 50.00);
INSERT INTO @T (SysInvNum, REF1, LineBalance) VALUES (31, 300, -50.00);
INSERT INTO @T (SysInvNum, REF1, LineBalance) VALUES (32, 300, 50.00);
INSERT INTO @T (SysInvNum, REF1, LineBalance) VALUES (33, 300, -50.00);
INSERT INTO @T (SysInvNum, REF1, LineBalance) VALUES (34, 300, 50.00);
INSERT INTO @T (SysInvNum, REF1, LineBalance) VALUES (41, 400, 50.00);
INSERT INTO @T (SysInvNum, REF1, LineBalance) VALUES (42, 400, -50.00);
INSERT INTO @T (SysInvNum, REF1, LineBalance) VALUES (43, 400, 50.00);
INSERT INTO @T (SysInvNum, REF1, LineBalance) VALUES (44, 400, -50.00);
INSERT INTO @T (SysInvNum, REF1, LineBalance) VALUES (45, 400, 50.00);
Run Code Online (Sandbox Code Playgroud)
我添加了几个有多个错误的案例.
SELECT
SysInvNum
, REF1
, LineBalance
, ROW_NUMBER() OVER(PARTITION BY REF1, LineBalance ORDER BY SysInvNum) AS rn
, COUNT(*) OVER(PARTITION BY REF1, ABS(LineBalance)) AS cc1
FROM @T AS TT
Run Code Online (Sandbox Code Playgroud)
这是结果集:
SysInvNum REF1 LineBalance rn cc1
11 100 50.00 1 3
12 100 -50.00 1 3
13 100 50.00 2 3
21 200 -50.00 1 3
23 200 50.00 1 3
22 200 -50.00 2 3
31 300 -50.00 1 4
32 300 50.00 1 4
33 300 -50.00 2 4
34 300 50.00 2 4
41 400 50.00 1 5
42 400 -50.00 1 5
43 400 50.00 2 5
44 400 -50.00 2 5
45 400 50.00 3 5
3341758 14598 73.19 1 2
3344296 14598 -73.19 1 2
3344298 14598 281.47 1 1
3344297 14602 -95.98 1 1
3344299 14602 558.83 1 1
Run Code Online (Sandbox Code Playgroud)
您可以看到那些有错误的行计数> 1.此外,错误对具有相同的行号.因此,我们需要删除/隐藏那些计数> 1的行和那些具有两个相同行号的行.
WITH
CTE_rn
AS
(
SELECT
SysInvNum
, REF1
, LineBalance
, ROW_NUMBER() OVER(PARTITION BY REF1, LineBalance ORDER BY SysInvNum) AS rn
, COUNT(*) OVER(PARTITION BY REF1, ABS(LineBalance)) AS cc1
FROM @T AS TT
)
, CTE_ToRemove
AS
(
SELECT
SysInvNum
, REF1
, LineBalance
, COUNT(*) OVER(PARTITION BY REF1, rn) AS cc2
FROM CTE_rn
WHERE CTE_rn.cc1 > 1
)
SELECT *
FROM CTE_ToRemove
WHERE CTE_ToRemove.cc2 = 2
Run Code Online (Sandbox Code Playgroud)
这是另一个中间结果:
SysInvNum REF1 LineBalance cc2
12 100 -50.00 2
11 100 50.00 2
21 200 -50.00 2
23 200 50.00 2
32 300 50.00 2
31 300 -50.00 2
33 300 -50.00 2
34 300 50.00 2
42 400 -50.00 2
41 400 50.00 2
43 400 50.00 2
44 400 -50.00 2
3344296 14598 -73.19 2
3341758 14598 73.19 2
Run Code Online (Sandbox Code Playgroud)
现在,我们把所有这些放在一起.
WITH
CTE_rn
AS
(
SELECT
SysInvNum
, REF1
, LineBalance
, ROW_NUMBER() OVER(PARTITION BY REF1, LineBalance ORDER BY SysInvNum) AS rn
, COUNT(*) OVER(PARTITION BY REF1, ABS(LineBalance)) AS cc1
FROM @T AS TT
)
, CTE_ToRemove
AS
(
SELECT
SysInvNum
, REF1
, LineBalance
, COUNT(*) OVER(PARTITION BY REF1, rn) AS cc2
FROM CTE_rn
WHERE CTE_rn.cc1 > 1
)
SELECT *
FROM @T AS TT
WHERE
TT.SysInvNum NOT IN
(
SELECT CTE_ToRemove.SysInvNum
FROM CTE_ToRemove
WHERE CTE_ToRemove.cc2 = 2
)
ORDER BY SysInvNum;
Run Code Online (Sandbox Code Playgroud)
结果:
SysInvNum REF1 LineBalance
13 100 50.00
22 200 -50.00
45 400 50.00
3344297 14602 -95.98
3344298 14598 281.47
3344299 14602 558.83
Run Code Online (Sandbox Code Playgroud)
注意,最终结果没有REF = 300的任何行,因为有两个纠正的错误,它们完全相互平衡.
大多数 AR/计费系统将“贷项凭证”(负金额)视为与现金类似,在这种情况下,-73.19 将应用于 73.19,LineBalance就像客户已支付该金额一样,从而导致余额为 0 美元。
选项1:
您是否在此系统中处理现金收据和申请?如果是这样,您可以从这些现金申请表中提取数据来显示 SysInvNum 3344296 和 3341758 之间的联系。
选项 2:
我假设该PayAdjust列用于减少客户付款后的余额,并且 LineBalance 是一个计算列,即Charges + PayAdjust。
大多数情况下,发生这种情况时,AR 部门将负责将贷项凭证应用于未结发票,以便该PayAdjust列在 2 行之间净值为 0 美元,这将导致LineBalance2 行中的每行也为 0 美元行。这可能只是正在使用的系统的培训问题。
这将导致有问题的 3 行看起来像这样,所以您没有问题,您只需通过添加到where LineBalance <> 0您的查询中来排除这些行,因为 AR 部门(它首先应用了信用,因此知道答案对于这个问题)明确说明了LineBalance信用证适用于:
选项 2 首选数据结构:
SysInvNum REF1 Charges PayAdjust LineBalance
----------- ----------- --------------------- --------------------- ---------------------
3344298 14598 281.47 0.00 281.47
3344296 14598 -73.19 73.19 0.00
3341758 14598 73.19 -73.19 0.00
Run Code Online (Sandbox Code Playgroud)
选项 3:
如果没有选项 1 或选项 2 中的这些数据,您就会做出许多假设,并面临无意中隐藏错误行的风险。
话虽如此,这里有一个查询尝试执行您所要求的操作,但我强烈建议您与 AR 部门联系,看看他们是否可以更新这些记录的“PayAdjust”。
我添加了几个可能导致问题的场景测试用例,但这可能无法涵盖所有基础。
对于相同的 REF1 和相同的 DueDate,此查询将仅隐藏为正值找到一个不同的匹配负值的行。它还确保原始收费发票 ID 位于贷项之前,因为可以假设贷项不会在实际收费之前发生(测试用例 6 仍然显示两行,因为贷项具有在收费之前发生的 SysInvNum) )。如果每个 找到多次匹配REF1, DueDate, and LineBalance,则不会隐藏相应的费用和信用额度(测试用例 2 和 4)。测试用例 3 的总和为 0,但它仍然显示所有 3 行,因为 LineBalance 值不完全匹配。这些都是我为处理边缘情况所做的假设,因此可以根据需要进行调整。
CREATE TABLE #SysInvTable (SysInvNum int not null primary key, REF1 int, Charges money, PayAdjust money, LineBalance as Charges + PayAdjust, DueDate date, REF2 int, Remark varchar(50), REM varchar(50));
INSERT INTO #SysInvTable(SysInvNum, REF1, Charges, PayAdjust, DueDate, Remark)
VALUES
--.....................................
--Your test case
(3344298, 14598, 281.47, 0, '2014-12-08','Your original test case. This one should stay.')
, (3344296, 14598, -73.19, 0, '2014-12-08',null)
, (3341758, 14598, 73.19, 0, '2014-12-08',null)
--.....................................
--Test case 2: How do you match these up?
, (2001, 2, 73.19, 0, '2015-01-06','Charge 2.1')
, (2002, 2, 73.19, 0, '2015-01-06','Charge 2.2')
, (2003, 2, 73.19, 0, '2015-01-06','Charge 2.3')
, (2004, 2, -73.19, 0, '2015-01-06','Credit for charge 2.3')
, (2005, 2, -73.19, 0, '2015-01-06','Credit for charge 2.1')
--.....................................
--Test case 3
, (3001, 3, 73.19, 0, '2015-01-06','Charge 3.1')
, (3002, 3, 73.19, 0, '2015-01-06','Charge 3.2')
, (3003, 3, -146.38, 0, '2015-01-06','Credit for charges 3.1 and 3.2')
--.....................................
--Test case 4: Do you hide 4001 or 4002?
, (4001, 4, 73.19, 0, '2015-01-06','Cable')
, (4002, 4, 73.19, 0, '2015-01-06','Internet')
, (4003, 4, -73.19, 0, '2015-01-06','Misc Credit')
--.....................................
--Test case 5: remove all lines except the first
, (5000, 5, 9.99, 0, '2015-01-06','Charge 5.0 (Should stay)')
, (5001, 5, 11.11, 0, '2015-01-06','Charge 5.1')
, (5002, 5, 22.22, 0, '2015-01-06','Charge 5.2')
, (5003, 5, 33.33, 0, '2015-01-06','Charge 5.3')
, (5004, 5, -11.11, 0, '2015-01-06','Credit for charge 5.1')
, (5005, 5, -33.33, 0, '2015-01-06','Credit for charge 5.3')
, (5006, 5, -22.22, 0, '2015-01-06','Credit for charge 5.2')
--.....................................
--Test case 6: credit occurs before charge, so keep both
, (6000, 6, -73.19, 0, '2015-01-06','Credit occurs before charge')
, (6001, 6, 73.19, 0, '2015-01-06','Charge 6.1')
;
SELECT i.*
FROM #SysInvTable i
WHERE i.SysInvNum not in
(
SELECT IngoreInvNum = case when c.N = 1 then max(t.SysInvNum) else min(t2.SysInvNum) end
FROM #SysInvTable t
INNER JOIN #SysInvTable t2
ON t.ref1 = t2.ref1
AND t.DueDate = t2.DueDate
CROSS APPLY (SELECT 1 AS N UNION ALL SELECT 2 as N) AS c --used to both both T and T2 SysInvNum's to exclude
WHERE 1=1
AND t.LineBalance > 0 AND t2.LineBalance < 0
AND t.SysInvNum < t2.SysInvNum --make sure the credit came in after the positive SysInvNum
AND t.LineBalance = t2.LineBalance * -1
GROUP BY t.REF1, t.DueDate, abs(t.LineBalance), c.n
HAVING Count(*) = 1
)
;
DROP TABLE #SysInvTable;
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
2437 次 |
| 最近记录: |