我的查询将导致在我们的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值。
答案 0 :(得分:5)
我会添加一个包含显式标记的字段,告诉您某个指控是错误/错误的反转然后过滤掉这些行是微不足道的。即时执行此操作可能会使您的报告速度变慢。
但是,要解决给定的问题,我们可以这样做。该解决方案假定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);
我添加了几个有多个错误的案例。
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
这是结果集:
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
您可以看到那些有错误的行计数>另外,错误对具有相同的行号。因此,我们需要删除/隐藏那些有计数>的行。 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
这是另一个中间结果:
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
现在,我们把所有这些放在一起。
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;
结果:
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
注意,最终结果没有REF = 300的任何行,因为有两个纠正的错误,它们完全相互平衡。
答案 1 :(得分:3)
大多数AR /结算系统将“贷项通知单”(负数)视为与现金类似,在这种情况下,-73.19将应用于73.19 LineBalance
,就像客户已支付该金额一样,结果为0美元。
选项1:
您是否处理此系统中的现金收据和应用程序?如果是这样,您可以从这些现金申请表中提取数据,以显示SysInvNum 3344296和3341758之间的关系。
选项2:
我假设PayAdjust
列用于在客户付款后减少余额,而LineBalance是一个Charges + PayAdjust
的计算列。
大多数情况下,AR部门负责将贷项凭证应用于未结发票,以便PayAdjust
列在2行之间净赚0美元,这将导致{ {1}}在每两行中也是$ 0。它可能只是正在使用的系统的培训问题。
这会导致有问题的3行看起来像这样,所以你没有问题,你只需要通过将LineBalance
添加到查询中来排除行,因为AR部门(应用了信用额度)开头,因此知道这个问题的答案)明确说明信用适用于where LineBalance <> 0
:
选项2首选数据结构:
LineBalance
选项3:
如果没有来自选项1或2的数据,您可以做出许多假设,并冒着无意中隐藏错误行的风险。
话虽如此,这是一个试图做你要求的查询,但我强烈建议检查AR部门,看看他们是否可以为这些记录更新“PayAdjust”。
我添加了几个可能导致问题的情景测试用例,但这可能无法覆盖所有基础。
对于相同的REF1和相同的DueDate,此查询仅隐藏为正值找到一个不同匹配负值的行。它还确保原始收费发票ID在信用之前,因为可以假设在实际收费之前不会发生信用(测试案例6显示两行仍然是因为信用证在收费之前发生了SysInvNum )。如果每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
找到多次匹配,则不会隐藏相应的费用和信用额度(测试用例2和4)。测试用例3总计为0,但它仍显示所有3行,因为LineBalance值不完全匹配。这些都是我处理边缘情况的假设,因此可以根据需要进行调整。
REF1, DueDate, and LineBalance
答案 2 :(得分:0)
它很笨重,但是这可以让你找出匹配的负面违规者。您需要从结果集中排除两列中的sysInvNum
Create table #tmp( SysInvNum int,Ref1 int, LineBalance decimal(8,2))
insert into #tmp
values(3344299,14602,558.83)
,(3344298,14598,281.47)
,(3344297,14602,-95.98)
,(3344296,14598,-73.19)
,(3341758,14598,73.19)
--Select * From #tmp
Select *
INTO #t1
From #tmp
Where LineBalance < 0
--Select * From #t1
Select SysInvNum1 = #tmp.SysInvNum, SysInvNum2 = #T1.SysInvNum
INTO #T2
From #tmp
LEFT JOIN #t1 On #tmp.Ref1 = #T1.Ref1 and #tmp.LineBalance = -#T1.LineBalance
where #t1.SysInvNum is not null
Select * From
#tmp
Where SysInvNum not in(
Select SysInvNum1 from #t2
union Select SysInvNum2 from #t2
)
drop table #tmp
drop table #t1
drop table #t2
答案 3 :(得分:0)
此解决方案适用于仅限SQL Server 2012 ,但如果将来有人必须做类似事情,则决定将其保留在此处,因为它非常简单。
...
如果它们的总和为0并且它们之间没有其他事务(并且在正事务之后发生否定事务),则应仅删除特定接收者的两个事务。它更加保守和安全。
应该有关于交易顺序的信息。类似日期列的东西。比你应该通过此列而不是PARTITION BY语句中的PRIMARY KEY列进行排序。
IF OBJECT_ID('Receipts', 'U') IS NOT NULL
DROP TABLE Receipts
CREATE TABLE Receipts
(
SysInvNum INT PRIMARY KEY IDENTITY(1,1),
REF1 INT,
LineBalance DECIMAL(10,2)
)
INSERT INTO Receipts
values
(14602,558.83),
(14598,281.47),
(14602,-95.98),
(14598,73.19),
(14598,-73.19),
(14598,73.19),
(14598,73.19),
(14598, 215.6),
(14598,73.19)
WITH ghosts AS
(
SELECT SysInvNum, REF1, LineBalance,
LAG(LineBalance, 1, 0) OVER (PARTITION BY REF1 ORDER BY SysInvNum) PreviousLineBalance,
LEAD(LineBalance, 1, 0) OVER (PARTITION BY REF1 ORDER BY SysInvNum) NextLineBalance
FROM Receipts
)
SELECT r.SysInvNum, r.REF1, r.LineBalance
FROM Receipts r
JOIN ghosts g On (r.SysInvNum = g.SysInvNum)
WHERE NOT (g.LineBalance + g.PreviousLineBalance = 0 AND g.LineBalance < 0)
AND NOT (g.LineBalance + g.NextLineBalance = 0 AND g.LineBalance > 0)
ORDER BY r.SysInvNum