使用的表:
1)v(日期d,名称c(25),desc c(50),借方n(7),贷方n(7))
'v'中的名称是指vn table中的名称
2)vn(日期d,名称c(25),类型c(25),obal n(7))
'vn'中的名称是主键,不同的名称按类型
分组例如:姓名abc,def,ghi属于'bank'类型,名称为xyz,pqr属于'ledger'类型,...
我有这样的查询:
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
它运行正常,但唯一的问题是,obal是一个值,在表'vn'中每个名称只输入一次,但是对于表'v'中每次计算信用借方的查询,obal会被多次添加并在OpBal下显示。当查询被修改如下:
SELECT vn.type, vn.obal + SUM(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
它显示错误消息,例如“分组子句丢失或无效”!
RDBMS使用MS Visual Foxpro 9. sd和ed是用于查询目的的日期类型变量,其中sd&lt;编辑。
请帮助我获得预期的结果。非常感谢。
答案 0 :(得分:0)
几分钟前我第一次看到带有VFP的SQL的SQL语法,所以这很可能充满了错误,但作为一种“猜测的预感”:
SELECT vn.type,
SUM(vn.obal + (SELECT SUM(IIF(v.date < sd, v.credit-v.debit, 0))
FROM v
WHERE v.name = vn.name)) OpBal,
SUM(SELECT SUM(IIF(BETWEEN(v.date, sd, ed), v.credit-v.debit, 0))
FROM v
WHERE v.name = vn.name) CurBal
FROM vn
GROUP BY vn.type
ORDER BY vn.type
HAVING OpBal + CurBal != 0
基本上,我只是将v中的选择转换为子选择以避免重复vn.obal。对于v而言,在将它们全部加在一起之前首先得到个人的总和应该无关紧要。
答案 1 :(得分:0)
SET ENGINEBEHAVIOR 80
默认为VFP 9
SET ENGINEBEHAVIOR 90
要求所有非分组列都要合并。
接下来......看起来你正在处理的表中有非常糟糕的列... VFP中的3个保留字...“日期”,“名称”和“类型”,但是你没问题使用alias.column引用在查询中限定它们。
以下示例代码将创建您在问题中描述的结构的临时表(游标)。我还插入了一些样本数据并模拟了你的“sd”(开始日期)和“ed”(结束日期)变量
CREATE CURSOR vn;
( date d, ;
name c(25), ;
type c(25), ;
obal n(7) )
INSERT INTO vn VALUES ( CTOD( "5/20/2012" ), "person 1", "person type 1", 125 )
INSERT INTO vn VALUES ( CTOD( "5/20/2012" ), "person 2", "another type ", 2155 )
CREATE CURSOR v;
( date d, ;
name c(25), ;
desc c(50), ;
debit n(7), ;
credit n(7))
INSERT INTO V VALUES ( CTOD( "6/1/2012" ), "person 1", "description 1", 10, 32 )
INSERT INTO V VALUES ( CTOD( "6/2/2012" ), "person 1", "desc 2", 235, 123 )
INSERT INTO V VALUES ( CTOD( "6/3/2012" ), "person 1", "desc 3", 22, 4 )
INSERT INTO V VALUES ( CTOD( "6/4/2012" ), "person 1", "desc 4", 53, 36 )
INSERT INTO V VALUES ( CTOD( "6/5/2012" ), "person 1", "desc 5", 31, 3 )
INSERT INTO V VALUES ( CTOD( "6/1/2012" ), "person 2", "another 1", 43, 664 )
INSERT INTO V VALUES ( CTOD( "6/4/2012" ), "person 2", "more desc", 78, 332 )
INSERT INTO V VALUES ( CTOD( "6/6/2012" ), "person 2", "anything", 366, 854 )
sd = CTOD( "6/3/2012" ) && start date of transactions
ed = DATE() && current date as the end date...
现在,查询......您正在尝试按类型获取群组,但每人(姓名)需要按人数预先汇总。现在,您似乎试图在开始日期(sd)之前获得总交易余额作为给定时间点的基础,然后查看相关开始/结束日期的活动。首先执行此操作,但不要处理从“vn”表中添加“obal”列。由于它需要按列分组非聚合,我只想使用列的“MAX()”。既然它是以PK(名称)为基础的,那么你最终会得到它的一切,但是随着累积的事务总数,你的所有数据都会通过...预先汇总成一行...
select;
vn.name,;
vn.type,;
MAX( vn.obal ) as BalByNameOnly,;
SUM( IIF( v.date < sd, v.credit-v.debit, 000000.00 )) OpBal, ;
SUM( IIF( BETWEEN(v.date, sd, ed), v.credit - v.debit, 000000.00 )) CurBal ;
FROM ;
v,;
vn ;
WHERE ;
v.name = vn.name;
GROUP BY ;
vn.Name,;
vn.Type;
INTO ;
CURSOR C_JustByName READWRITE
这个结果(来自我的样本数据)看起来像......
Name Type BalByNameOnly OpBal CurBal
person 1 person type 1 125 -90 -63
person 2 another type 2155 621 742
您按类型获取的最终聚合,您只需查询上面的结果“cursor”(C_JustByName)并使用IT按类型获取您的分组,等等...
SELECT ;
JBN.type, ;
JBN.BalByNameOnly - JBN.OpBal as OpBal,;
JBN.CurBal ;
FROM ;
C_JustByName JBN ;
GROUP BY ;
vn.type ;
ORDER BY ;
vn.type ;
HAVING ;
OpBal + CurBal != 0;
INTO ;
CURSOR C_Final
现在,我只是简化了上述内容,因为我不知道你真正想要的是“VN”中的日期(看起来像一张客户表),其日期不清楚其目的和关于交易表的oBal列。
关于VFP的好处是,您可以在不创建永久表的情况下查询临时游标,并在此之后使用IT作为任何查询的基础...它有助于不必在查询内嵌入查询的可读性查询。它还允许您查看每个图层的结果,并知道您在继续下一个查询阶段之前得到了您期望的答案......
希望这会帮助您朝着您想要解决的方向前进。
答案 2 :(得分:0)
再一次,这个问题被撞到了前面:(在我像这样发表评论之前:
不幸的是,这个6年前的问题被碰到了 到首页:(原因是这个问题饿了一些 说明和设计都在尖叫缺陷。不知道 这些细节,没有答案会很好。 1)永远不要依赖旧的 enginebehavior解决此错误。这是一个错误,已更正。 依靠错误不是解决之道。 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的查询:
本地标准版 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重复了3次,因为v中有3个条目。求和将使其变为300,而恰好是100。
使用诸如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类型(1-to-many的1面)可以。
话虽如此,并添加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