You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何避免SELECT子句中使用子查询实现文档金额统计?

问题:避免SELECT子查询实现文档金额与分配金额统计

表结构与测试数据

CREATE TABLE document_header 
(
    id int, 
    originalAmount decimal(5, 2), 
    doc_type char(2)
)

INSERT INTO document_header(id, originalAmount, doc_type) 
VALUES (1001, '200.00', 'PV'),
       (1002, '150.00', 'PV'),
       (1003, '300.00', 'IV'),
       (1004, '400.00', 'IV'),
       (1005, '600.00', 'IV')

CREATE TABLE document_allocation 
(
    id int, 
    allocatedto int, 
    allocatedfrom int, 
    allocatedamount decimal(5, 2)
)

INSERT INTO document_allocation 
VALUES (1, 1003, 1001, '100.00'),
       (2, 1004, 1001, '50.00'),
       (3, 1003, 1002, '50.00'),
       (4, 1005, 1001, '50.00'),
       (5, 1004, 1002, '50.00'),
       (6, 1003, 1001, '20.00')

预期结果

originalDocumentIddocumentOriginalAmountallocatedByallocatedamount
1003300.001001120.00
1003300.00100250.00
1004400.00100150.00
1004400.00100250.00
1005600.00100130.00

现有问题

现有带SELECT子查询的SQL可得到预期结果,但需要避免SELECT子句中的子查询:

SELECT
    originalDocument.id AS OriginalDocumentID,
    document_header.id AS allocatedBy,
    (SELECT SUM(document_header_a.originalAmount) 
     FROM document_header document_header_a 
     WHERE document_header_a.id = originalDocument.id),
    SUM(document_allocation.allocatedamount) AS amountAllocated
FROM
    document_header,
    document_allocation,
    document_header originalDocument
WHERE
    document_header.id = document_allocation.allocatedfrom AND
    originalDocument.id = document_allocation.allocatedto
GROUP BY
    originalDocument.id,
    document_header.id

尝试直接聚合原始金额时,出现金额翻倍问题(如1003对应1001的documentOriginalAmount变成600.00):

SELECT
    originalDocument.id AS OriginalDocumentID,
    document_header.id AS allocatedBy,
    SUM(originalDocument.originalAmount) AS documentOriginalAmount,
    SUM(document_allocation.allocatedamount) AS amountAllocated
FROM
    document_header,
    document_allocation,
    document_header originalDocument
WHERE
    document_header.id = document_allocation.allocatedfrom AND
    originalDocument.id = document_allocation.allocatedto
GROUP BY
    originalDocument.id,
    document_header.id

错误执行结果:

OriginalDocumentIDdocumentOriginalAmountallocatedByamountAllocated
1003600.001001120.00
1003300.00100250.00
1004400.00100150.00
1004400.00100250.00
1005600.00100130.00

解决方案

方法1:先聚合分配表,再关联表头表

先对document_allocation按目标文档(allocatedto)和来源文档(allocatedfrom)分组求和,再关联document_header获取原始金额,避免重复计算:

SELECT
    da.allocatedto AS originalDocumentId,
    dh.originalAmount AS documentOriginalAmount,
    da.allocatedfrom AS allocatedBy,
    da.total_allocated AS allocatedamount
FROM (
    SELECT 
        allocatedto,
        allocatedfrom,
        SUM(allocatedamount) AS total_allocated
    FROM document_allocation
    GROUP BY allocatedto, allocatedfrom
) da
JOIN document_header dh ON dh.id = da.allocatedto
ORDER BY da.allocatedto, da.allocatedfrom;

方法2:用非SUM聚合函数获取原始金额

由于每个文档的originalAmount是唯一值,分组后用MAX()/MIN()/AVG()等聚合函数代替SUM(),即可避免重复累加:

SELECT
    originalDocument.id AS originalDocumentId,
    document_header.id AS allocatedBy,
    MAX(originalDocument.originalAmount) AS documentOriginalAmount,
    SUM(document_allocation.allocatedamount) AS allocatedamount
FROM
    document_header
JOIN document_allocation ON document_header.id = document_allocation.allocatedfrom
JOIN document_header originalDocument ON originalDocument.id = document_allocation.allocatedto
GROUP BY
    originalDocument.id,
    document_header.id
ORDER BY originalDocument.id, allocatedBy;

两种方法均无需在SELECT子句中使用子查询,且能得到符合预期的结果。

内容的提问来源于stack exchange,提问作者learning

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.13 23:25:36