再一次,这个问题被推到了前面:(在我发表评论之前:
不幸的是,这个 6 年前的问题被撞到了头版 :( 原因是这个问题渴望得到一些解释,而设计中充满了缺陷。不知道这些细节,没有答案是好的。1)从不永远依靠旧的引擎行为来解决此错误。这是一个错误并已更正。依靠错误不是要走的路。2)要创建一个日期值,永远不要通过从字符串转换来做到这一点。这取决于设置。最好使用可靠的 date()、datetime() 函数或严格的 date\datetime 文字。
无论如何,该评论仍然存在,还有更多。
让我们根据我对问题的理解添加更多关于缺陷和回复的信息。
在问题中,OP 说:“
SELECT vn.type, SUM(vn.obal + IIF(v.date < sd, v.credit-v.debit, 0)) OpBal, ;
SUM(IIF(BETWEEN(v.date, sd, ed), v.credit-v.debit, 0)) CurBal ;
FROM v, vn WHERE v.name = vn.name GROUP BY vn.type ;
ORDER BY vn.type HAVING OpBal + CurBal != 0
工作正常。”
但是当然,任何使用 SQL 的经验丰富的开发人员都会立即发现它不能正常工作,结果可能只是巧合。让我们弄清楚为什么它不会真正起作用。首先让我们创建一些描述 OP 数据的游标:
CREATE CURSOR vn ( date d, name c(25), type c(25), obal n(7) )
INSERT INTO vn (date, name, type, obal) VALUES ( DATE(2012,5,20), "abc", "bank", 100 )
INSERT INTO vn (date, name, type, obal) VALUES ( DATE(2012,5,20), "def", "bank", 200 )
INSERT INTO vn (date, name, type, obal) VALUES ( DATE(2012,5,20), "ghi", "bank", 300 )
INSERT INTO vn (date, name, type, obal) VALUES ( DATE(2012,5,20), "xyz", "ledger", 400 )
INSERT INTO vn (date, name, type, obal) VALUES ( DATE(2012,5,20), "pqr", "ledger", 500 )
CREATE CURSOR v ( date d, name c(25), desc c(50), debit n(7), credit n(7))
INSERT INTO V (date,name,desc,debit,credit) VALUES ( DATE(2012,6,1), "abc", "description 1", 50, 0 )
INSERT INTO V (date,name,desc,debit,credit) VALUES ( DATE(2012,6,2), "abc", "description 1", 60, 0 )
INSERT INTO V (date,name,desc,debit,credit) VALUES ( DATE(2012,6,3), "abc", "description 1", 70, 0 )
INSERT INTO V (date,name,desc,debit,credit) VALUES ( DATE(2012,6,1), "def", "description 1", 50, 0 )
INSERT INTO V (date,name,desc,debit,credit) VALUES ( DATE(2012,6,2), "def", "description 1", 60, 0 )
INSERT INTO V (date,name,desc,debit,credit) VALUES ( DATE(2012,6,3), "def", "description 1", 70, 0 )
INSERT INTO V (date,name,desc,debit,credit) VALUES ( DATE(2012,6,1), "ghi", "description 1", 50, 0 )
INSERT INTO V (date,name,desc,debit,credit) VALUES ( DATE(2012,6,2), "ghi", "description 1", 60, 0 )
INSERT INTO V (date,name,desc,debit,credit) VALUES ( DATE(2012,6,4), "xyz", "description 1", 50, 0 )
INSERT INTO V (date,name,desc,debit,credit) VALUES ( DATE(2012,6,5), "xyz", "description 1", 60, 0 )
INSERT INTO V (date,name,desc,debit,credit) VALUES ( DATE(2012,6,6), "pqr", "description 1", 50, 0 )
INSERT INTO V (date,name,desc,debit,credit) VALUES ( DATE(2012,6,7), "pqr", "description 1", 60, 0 )
INSERT INTO V (date,name,desc,debit,credit) VALUES ( DATE(2012,6,8), "pqr", "description 1", 70, 0 )
让我们对这些数据运行 OP 的查询:
LOCAL sd,ed sd = date(2012,6,1) && 交易开始日期 ed = DATE() && 当前日期作为结束日期...
SELECT vn.type, SUM(vn.obal + IIF(v.date < sd, v.credit-v.debit, 0)) OpBal, ;
SUM(IIF(BETWEEN(v.date, sd, ed), v.credit-v.debit, 0)) CurBal ;
FROM v, vn WHERE v.name = vn.name GROUP BY vn.type ;
ORDER BY vn.type HAVING OpBal + CurBal != 0
我们得到如下结果:
TYPE OPBAL CURBAL
------- ----- ------
bank 1500 -470
ledger 2300 -290
这显然是不正确的。通过这样的查询,您获得的贷方或借方越多,您的期初余额就越多。让我们看看为什么会发生这种情况,删除分组依据和聚合,检查我们真正总结的内容:
SELECT vn.type, vn.name, v.date, vn.obal, v.credit, v.debit ;
FROM v, vn ;
WHERE v.name = vn.name
输出:
TYPE NAME DATE OBAL CREDIT DEBIT
bank abc 06/01/2012 100 0 50
bank abc 06/02/2012 100 0 60
bank abc 06/03/2012 100 0 70
bank def 06/01/2012 200 0 50
bank def 06/02/2012 200 0 60
bank def 06/03/2012 200 0 70
bank ghi 06/01/2012 300 0 50
bank ghi 06/02/2012 300 0 60
ledger xyz 06/04/2012 400 0 50
ledger xyz 06/05/2012 400 0 60
ledger pqr 06/06/2012 500 0 50
ledger pqr 06/07/2012 500 0 60
ledger pqr 06/08/2012 500 0 70
您可以看到,假设 'abc' OBal 100 重复了 3 次,因为 v 中有 3 个条目。当它只有 100 时,求和会使它变成 300。
当您使用像 SUM() 或 AVG() 这样的聚合时,您应该先在没有连接的情况下进行聚合,然后再进行连接。您仍然可以使用连接进行聚合,提供,连接会产生一对多的关系。如果上述结果集是:
TYPE NAME OBAL CREDIT DEBIT
bank abc 100 0 180
bank def 200 0 180
bank ghi 300 0 110
ledger xyz 400 0 110
ledger pqr 500 0 180
可以 SUM() BY 类型(一对多的一侧)。
话虽如此,添加 VFP 支持子查询让我们编写一个解决方案:
Local sd,ed
sd = Date(2012,6,1) && start date of transactions
ed = Date() && current date as the end date...
Select vn.Type, Sum(vn.OBal - tmp.TotCd) As Opbal, Sum(tmp.Curbal) As Curbal ;
FROM vn ;
LEFT Join ;
(Select v.Name, Sum(Iif(v.Date < sd, v.credit-v.debit, 0)) TotCd, ;
SUM(Iif(Between(v.Date, sd, ed), v.credit-v.debit, 0)) Curbal ;
FROM v ;
GROUP By v.Name ) tmp On tmp.Name = vn.Name ;
GROUP By vn.Type ;
ORDER By vn.Type ;
HAVING Sum(vn.OBal - tmp.TotCd + tmp.Curbal) != 0
我们得到了我们想要的:
TYPE OPBAL CURBAL
------- ----- ------
bank 600 -470
ledger 900 -290