SAP B1 AR INVOICE 与 Incoming Payment 查询无结果
结论
查询结果为空,主要有两个原因:
RCT2应通过发票内部键关联OINV.DocEntry,不能使用OINV.DocNum = RCT2.BaseAbs。RCT1和RCT3使用了INNER JOIN,相当于要求同一笔 Incoming Payment 既有支票明细,又有信用卡明细。大多数付款不满足这个条件,因此会被过滤掉。
SAP Business One 中的单据通常通过 DocEntry 关联。DocNum 是用户看到的单据编号。付款可能采用现金、银行转账、支票或信用卡,并不一定同时存在多种付款明细,所以 RCT1 和 RCT3 应使用 LEFT JOIN。
正确的表关系
各表之间的核心关系如下:
ORCT.DocEntry = RCT2.DocNum
RCT2.DocEntry = OINV.DocEntry
RCT2.InvType = 13
ORCT.DocEntry = RCT1.DocNum
ORCT.DocEntry = RCT3.DocNum
OINV.DocEntry = INV1.DocEntry
各表的用途如下:
ORCT:Incoming Payment 表头。RCT2:Incoming Payment 核销的单据。OINV:A/R Invoice 表头。INV1:A/R Invoice 行。RCT1:支票付款明细。RCT3:信用卡付款明细。OCRD:Business Partner 主数据。OWHS:仓库主数据。[@AUND]:用户自定义表。
RCT2.InvType = 13 将关联对象限定为 A/R Invoice,避免将贷项凭证、日记账等其他对象错误地关联到 OINV。
调整后的查询
SELECT
T5.DocNum AS INVOICENO,
T5.DocEntry AS INVOICE_DOCENTRY,
T0.DocNum AS PAYMENTNO,
T0.DocEntry AS PAYMENT_DOCENTRY,
T0.DocDate,
T0.TrsfrDate,
T0.TrsfrRef,
T0.CardName,
T0.DocTotal,
T4.VoucherNum,
T0.Comments,
T2.Phone1,
T0.CashSum,
T0.CreditSum,
T0.CheckSum,
T0.TrsfrSum,
T3.DueDate AS CHECKDATE,
T3.CheckNum AS CHECKNO,
T3.Details AS MAYBEBANKNAME,
T5.U_UnitCode,
T5.U_Type,
T7.WhsName,
T7.City,
T8.U_FloorNo
FROM ORCT T0
INNER JOIN RCT2 T1
ON T0.DocEntry = T1.DocNum
AND T1.InvType = 13
INNER JOIN OINV T5
ON T5.DocEntry = T1.DocEntry
INNER JOIN OCRD T2
ON T0.CardCode = T2.CardCode
LEFT JOIN RCT1 T3
ON T0.DocEntry = T3.DocNum
LEFT JOIN RCT3 T4
ON T0.DocEntry = T4.DocNum
LEFT JOIN INV1 T6
ON T5.DocEntry = T6.DocEntry
LEFT JOIN OWHS T7
ON T6.WhsCode = T7.WhsCode
LEFT JOIN [dbo].[@AUND] T8
ON T5.U_UnitCode = T8.Code;
查询中的显示字段也做了相应调整:
- 发票号取
OINV.DocNum,也就是T5.DocNum。 - Incoming Payment 的可见付款编号取
ORCT.DocNum,也就是T0.DocNum。 - 额外输出
DocEntry,便于排查内部关联关系。
为什么原查询会失败
1. 发票连接键错误
原查询使用了以下条件:
INNER JOIN OINV T5
ON T5.DocNum = T1.BaseAbs
DocNum 是显示给用户的业务编号,通常不用于连接单据表。Incoming Payment 的发票分配行通常通过 RCT2.DocEntry 保存被核销单据的内部键,因此应改为:
INNER JOIN OINV T5
ON T5.DocEntry = T1.DocEntry
AND T1.InvType = 13
如果当前数据库版本或本地化字段结构不同,应先检查 RCT2 中实际保存的 DocEntry、InvoiceId、BaseAbs 和 InvType 值。标准查询关系通常是 RCT2.DocEntry = OINV.DocEntry。
2. 付款方式表不应全部使用 INNER JOIN
原查询同时使用了:
INNER JOIN RCT1 ...
INNER JOIN RCT3 ...
这要求一笔付款必须同时包含:
RCT1中的支票记录;RCT3中的信用卡记录。
如果付款只使用银行转账、现金、支票或信用卡中的一种,就无法满足这两个条件。
应改为:
LEFT JOIN RCT1 ...
LEFT JOIN RCT3 ...
现金和银行转账金额主要保存在 ORCT 表头中,不要求存在对应的明细行。
3. RCT1、RCT3 应关联付款的 DocEntry
原查询使用了:
T0.DocNum = T3.DocNum
T0.DocNum = T4.DocNum
这组条件混用了可见单据编号和内部键。通常应写成:
T0.DocEntry = T3.DocNum
T0.DocEntry = T4.DocNum
虽然字段名是 DocNum,但 RCT1.DocNum 和 RCT3.DocNum 在这些子表中保存的是所属付款的内部键。
建议分段验证
查询没有结果时,可以逐层添加 JOIN,检查数据是在哪一层被过滤掉的。
先检查付款及其核销单据:
SELECT
T0.DocEntry,
T0.DocNum,
T1.InvType,
T1.DocEntry AS AppliedDocEntry,
T1.SumApplied
FROM ORCT T0
INNER JOIN RCT2 T1
ON T0.DocEntry = T1.DocNum;
然后只检查 A/R Invoice:
SELECT
T0.DocNum AS PaymentNo,
T2.DocNum AS InvoiceNo,
T1.SumApplied
FROM ORCT T0
INNER JOIN RCT2 T1
ON T0.DocEntry = T1.DocNum
AND T1.InvType = 13
INNER JOIN OINV T2
ON T2.DocEntry = T1.DocEntry;
确认这两段查询都有结果后,再依次添加 RCT1、RCT3、INV1、OWHS 和用户自定义表。
注意事项
- 一笔 Incoming Payment 可以核销多张发票,因此可能返回多行。
- 一张发票可以包含多个
INV1行,不同行还可能使用不同仓库。连接INV1后,结果行数会继续增加。 - 如果一笔付款有多个支票或多条信用卡记录,同时又关联多张发票,直接连接这些表可能造成笛卡尔式放大。例如,两张发票、两个支票和三个发票行可能组合出多条结果。
- 如果只需要发票表头的 UDF,不需要仓库信息,可以移除
INV1和OWHS,以减少重复行。 [@AUND]应使用LEFT JOIN。如果使用INNER JOIN,只要U_UnitCode为空、代码不存在或格式不完全一致,整条付款记录就会被过滤掉。- 如果需要排除已取消的付款或发票,可以根据业务需求添加
T0.Canceled = 'N'和T5.CANCELED = 'N'。这两个条件并不是解决空结果所必需的。
备注:内容仅供参考。
