我需要在PostgreSQL 9.1中提供现金流量报告。
在余额行(BalanceLine)中,函数(getBalanceLine)负责获取银行账户及其信用或借记头的总和。
需要将数字行(num_row
)减少到零,以向函数getBalanceLine
指示临时表必须DROP
。该临时表将平衡线结果保存为计算的“工作记忆”。
问题是函数num_row
上的getBalanceLine
变量没有根据我LOOP
子句的说明而减少。
以下是PL / pgSQL函数:
DROP FUNCTION IF EXISTS report_cash_flow();
CREATE FUNCTION report_cash_flow() RETURNS TABLE(Date date, Company varchar(128), Bank varchar(64), Partner varchar(128), Document varchar(64), Credit numeric, Debit numeric, Line integer, BalanceLine numeric) AS
$BODY$
DECLARE
num_row int := 0;
BEGIN
num_row = ( SELECT
COUNT(*)
FROM
account_move_line aml
INNER JOIN res_company rc ON rc.id = aml.company_id
INNER JOIN res_partner rp ON rp.id = aml.partner_id
INNER JOIN account_journal aj ON aj.id = aml.journal_id
INNER JOIN account_account aa ON aa.id = aml.account_id
WHERE
aml.state = 'valid'
AND aml.reconcile_id IS NULL );
FOR Date, Company, Bank, Partner, Document, Credit, Debit, Line, BalanceLine IN
SELECT
aml.date_maturity AS Date,
rc.name AS Company,
aj.name AS Bank,
rp.name AS Partner,
aml.name AS Document,
aml.credit AS Credit,
aml.debit AS Debit,
num_row AS Line,
getBalanceLine(aml.credit, aml.debit, num_row) AS BalanceLine
FROM
account_move_line aml
INNER JOIN res_company rc ON rc.id = aml.company_id
INNER JOIN res_partner rp ON rp.id = aml.partner_id
INNER JOIN account_journal aj ON aj.id = aml.journal_id
INNER JOIN account_account aa ON aa.id = aml.account_id
WHERE
aml.state = 'valid'
AND aml.reconcile_id IS NULL
ORDER BY
Document
LOOP
num_row := num_row - 1;
RAISE NOTICE '%', num_row;
RETURN NEXT;
END LOOP;
RETURN;
END;
$BODY$
LANGUAGE 'plpgsql';
SELECT * FROM report_cash_flow();
以下是查询的结果:
date company bank partner document credit debit line balanceline
01/10/2013 Company 1 Bank 1 Partner 1 00003621/1 0.00 520.56 4 1.024,00
01/10/2013 Company 1 Bank 2 Partner 2 00003622/1 32.00 0.00 4 922,00
09/10/2014 Company 1 Bank 1 Partner 3 00003623/1 0.00 18009.65 4 -17.087,65
10/10/2014 Company 1 Bank 2 Partner 4 00003624/1 6126.95 0.00 4 -10.960,70
以下是RAISE NOTICE '%', num_row
:
NOTICE: 4
NOTICE: 3
NOTICE: 2
NOTICE: 1
答案 0 :(得分:1)
提供FOR
循环行的查询在循环的第一次迭代之前执行 一次 。您必须在循环中调用函数getBalanceLine()
,而不是在基本查询中。
然而,你的整个方法都是不必要的冗长和昂贵。
CREATE FUNCTION report_cash_flow()
RETURNS TABLE(Date date, Company text, Bank text, Partner text, Document text, Credit numeric, Debit numeric, Line integer, BalanceLine numeric) AS
$func$
DECLARE
_iterator int := 0;
BEGIN
FOR Date, Company, Bank, Partner, Document, Credit, Debit, Line IN
SELECT aml.date_maturity AS Date -- alias useless
rc.name AS Company,
aj.name AS Bank,
rp.name AS Partner,
aml.name AS Document,
aml.credit AS Credit,
aml.debit AS Debit,
count(*) OVER () AS Line -- = initial num_row
FROM account_move_line aml
JOIN res_company rc ON rc.id = aml.company_id
JOIN res_partner rp ON rp.id = aml.partner_id
JOIN account_journal aj ON aj.id = aml.journal_id
JOIN account_account aa ON aa.id = aml.account_id
WHERE aml.state = 'valid'
AND aml.reconcile_id IS NULL
ORDER BY Document
LOOP
BalanceLine := getBalanceLine(Credit, Debit, Line - _iterator);
RETURN NEXT;
_iterator := _iterator + 1;
RAISE NOTICE '%', Line - _iterator;
END LOOP;
RETURN;
END
$func$ LANGUAGE plpgsql;
SELECT
中执行此操作。_iterator
我在_
前面加上变量以避免命名collisons。plpgsql
,它是一个标识符。您可以使用window functions这个单一的普通查询代替:
SELECT aml.date_maturity AS Date
, rc.name AS Company
, aj.name AS Bank
, rp.name AS Partner
, aml.name AS Document
, aml.credit
, aml.debit
, count(*) OVER () AS Line -- or the decreasing number?
, getBalanceLine(aml.credit
, aml.debit
, count(*) OVER () + 1 -
row_number() OVER (ORDER BY Document)) AS BalanceLine
FROM account_move_line aml
JOIN res_company rc ON rc.id = aml.company_id
JOIN res_partner rp ON rp.id = aml.partner_id
JOIN account_journal aj ON aj.id = aml.journal_id
JOIN account_account aa ON aa.id = aml.account_id
WHERE aml.state = 'valid'
AND aml.reconcile_id IS NULL
ORDER BY Document;
或使用更复杂的:
count(*) OVER (ORDER BY Document
ROWS BETWEEN CURRENT ROW AND UNBOUNDED FOLLOWING)
更多解释: