我有一张桌子 使用以下数据
Table X
Seq_no A Claim Payment Balance (to be calculated)
1 abc 100 10 90 (100-10)
2 abc 50 40 (90-50)
3 abc 20 20 (40-20)
1 xyz 150 10 140 (150-10)
1 qwe 200 10 190 (200-10)
我需要计算列余额。
我正在尝试使用以下查询 SQL>
Select
Seq_no, a, Claim, Payment,
CASE
When Seq_no =1
then (claim-Payment)
Else ( lag(Balance)- Payment over (order by Balance))
END as Balance
from table X
但是我收到了错误
ORA-00904: "Balance": invalid identifier
00904. 00000 - "%s: invalid identifier"
我认为这是因为Balance不是现有的列名。
是否有正确的方法来实现结果。?
更新 *我错过了重要的一部分。 *
我拥有的数据格式如下:
Table X
Seq_no A Claim Payment
1 abc 100 10
2 abc 100 50
3 abc 100 20
1 xyz 150 10
1 qwe 200 10
我需要以下格式的结果。
Table X
Seq_no A Claim Payment Balance (to be calculated)
1 abc 100 10 90 (100-10)
2 abc 50 40 (90-50)
3 abc 20 20 (40-20)
1 xyz 150 10 140 (150-10)
1 qwe 200 10 190 (200-10)
已完成Seq_no计算,以使索赔列为重复索赔的情况为空,我已经想到了这一点。
答案 0 :(得分:2)
在创建之前,您无法参考平衡。
您可以使用“运行总和”来实现您想要达到的目标。
请注意,我用A进行了分区,因为您希望每个A都有另一个余额。
Select
Seq_no, a, Claim, Payment,
sum(nvl(claim,0) - payment) over (partition by A order by seq_no) as Balance
from X;
结果:
SEQ_NO A CLAIM PAYMENT BALANCE
1 abc 100 10 90
2 abc 50 40
3 abc 20 20
1 qwe 200 10 190
1 xyz 150 10 140
编辑:对于较新的数据集,您只需要在seq = 1时将nvl函数替换为大小写:
Select
Seq_no,
a,
case when seq_no=1 then claim else 0 end as Claim,
Payment,
sum(case when seq_no=1 then claim else 0 end - payment)
over (partition by A order by seq_no) as Balance
from X;
答案 1 :(得分:2)
要将balance
用作列标识符,您必须深入一级,即将现有查询作为子查询。
工作演示:
SQL> WITH sample_data AS(
2 SELECT 1 Seq_no, 'abc' A, 100 Claim, 10 Payment FROM dual UNION ALL
3 SELECT 2 Seq_no, 'abc' A, NULL Claim, 50 FROM dual UNION ALL
4 SELECT 3 Seq_no, 'abc' A, NULL Claim, 20 FROM dual UNION ALL
5 SELECT 1 Seq_no, 'xyz' A, 150 Claim, 10 FROM dual UNION ALL
6 SELECT 1 Seq_no, 'qwe' A, 200 Claim, 10 FROM dual
7 )
8 -- end of sample_data mimicking real table
9 SELECT seq_no, A, claim, payment,
10 CASE
11 WHEN lag(balance) OVER(PARTITION BY A ORDER BY seq_no) IS NULL
12 THEN balance
13 ELSE lag(balance) OVER(PARTITION BY A ORDER BY seq_no) - payment
14 END balance
15 FROM
16 (SELECT seq_no, A, claim, payment,
17 CASE
18 WHEN seq_no = 1
19 THEN claim - payment
20 ELSE lag(claim - payment) OVER(PARTITION BY A ORDER BY seq_no) - payment
21 END balance
22 FROM sample_data
23 );
SEQ_NO A CLAIM PAYMENT BALANCE
---------- --- ---------- ---------- ----------
1 abc 100 10 90
2 abc 50 40
3 abc 20 20
1 qwe 200 10 190
1 xyz 150 10 140
SQL>
UPDATE :如果您的claim
值始终不为null,那么您可以执行运行差异:
SQL> WITH sample_data AS(
2 SELECT 1 Seq_no, 'abc' A, 100 Claim, 10 Payment FROM dual UNION ALL
3 SELECT 2 Seq_no, 'abc' A, 100 Claim, 50 FROM dual UNION ALL
4 SELECT 3 Seq_no, 'abc' A, 100 Claim, 20 FROM dual UNION ALL
5 SELECT 4 Seq_no, 'abc' A, 100 Claim, 10 FROM dual UNION ALL
6 SELECT 5 Seq_no, 'abc' A, 100 Claim, 10 FROM dual UNION ALL
7 SELECT 1 Seq_no, 'xyz' A, 150 Claim, 10 FROM dual UNION ALL
8 SELECT 1 Seq_no, 'qwe' A, 200 Claim, 10 FROM dual
9 )
10 -- end of sample_data mimicking real table
11 SELECT Seq_no,
12 a,
13 Claim,
14 Payment,
15 CASE
16 WHEN seq_no = 1
17 THEN claim - payment
18 ELSE SUM(claim - payment) over (partition BY A order by seq_no) - claim*(seq_no-1)
19 END balance
20 FROM sample_data;
SEQ_NO A CLAIM PAYMENT BALANCE
---------- --- ---------- ---------- ----------
1 abc 100 10 90
2 abc 100 50 40
3 abc 100 20 20
4 abc 100 10 10
5 abc 100 10 0
1 qwe 200 10 190
1 xyz 150 10 140
7 rows selected.
SQL>
答案 2 :(得分:-1)
发生错误是正确的,因为Balance不是表中的列。您需要添加该列。
更大的问题是,遗憾的是,使用单个SQL语句计算运行总计是不可能的。 SQL不太适合这样的操作。它可以使用游标在存储过程中完成,但最终结果是程序性的而不是基于集合的,因此性能会很差。以下是如何在SQL Server中执行此操作(作为示例,未经测试):
DECLARE PaymentCursor CURSOR FOR SELECT A, Claim, Payment FROM X ORDER BY A, Seq_no
OPEN PaymentCursor
DECLARE @A VARCHAR(16)
DECLARE @Claim MONEY
DECLARE @Payment MONEY
DECLARE @Balance MONEY
DECLARE @PreviousA VARCHAR(16)
SET @PreviousA = ''
FETCH NEXT FROM PaymentCursor INTO @A, @Claim, @Payment
WHILE @@FETCH_STATUS = 0
BEGIN
IF @A <> @PreviousA
BEGIN
SET @Balance = 0
SET @PreviousA = @A
END
SET @Balance = @Balance + @Claim - @Payment
UPDATE X SET Balance = @Balance WHERE CURRENT OF PaymentCursor
FETCH NEXT FROM PaymentCursor INTO @A, @Claim, @Payment
END
CLOSE PaymentCursor
DEALLOCATE PaymentCursor
如果您的应用程序确实需要知道与每个事务关联的帐户余额,则更好的方法是每次插入行时计算余额。将插入逻辑包装在存储过程中:
CREATE PROCEDURE InsertAndComputeBalance
@A VARCHAR(16),
@Claim MONEY,
@Payment MONEY
AS
DECLARE @MAX_Seq_no INTEGER = (SELECT MAX(Seq_no) FROM X WHERE A = @A)
INSERT INTO X
SELECT @MAX_Seq_no + 1, @A, @Claim, @Payment, Balance + @Claim - @Payment FROM X
WHERE A = @A AND Seq_no = @MAX_Seq_no
理论上你可以从一个触发器调用类似的逻辑,这样每次插入一行时都会自动执行,但触发器可能是邪恶的,所以要非常小心地使用这种方法。