从单个 SQL 查询中获取两个不同的值

Take two different values from a single SQL query

有没有办法 simplify/optimise 这个 mysql/mariadb 查询? 最终我需要来自单个查询的两个单独的数据:最新的交易名称和所有交易支付金额的总和。

这行得通但是很丑,因为它重复了 JOINS 和 WHERE 子句:

    SELECT
        SUM(btp.allocated_amount),
        (
        SELECT
            bt.name
        FROM
            `tabBank Transaction Payments` as btp
        LEFT JOIN
            `tabBank Transaction` bt ON bt.name=btp.parent
        WHERE
            btp.payment_document = 'Journal Entry'
        AND
            bt.docstatus = 1
        ORDER BY
            bt.date desc
        LIMIT 1
        ) AS name
        FROM
            `tabBank Transaction Payments` as btp
        LEFT JOIN
            `tabBank Transaction` bt ON bt.name=btp.parent
        WHERE
            btp.payment_document = 'Journal Entry'
        AND
            bt.docstatus = 1;

我认为这样的事情会奏效,但事实并非如此。根据 ORDER BY:

给出的名称是任意的,而不是第一个
        SELECT
        (SELECT SUM(allocated_amount)),
        (SELECT name LIMIT 1)
        FROM
        (
        SELECT
            btp.allocated_amount,
            bt.name
        FROM
            `tabBank Transaction Payments` as btp
        LEFT JOIN
            `tabBank Transaction` bt ON bt.name=btp.parent
        WHERE
            btp.payment_document = 'Journal Entry'
        AND
            bt.docstatus = 1
        ORDER BY
            bt.date desc
        ) AS temp;

编辑:

示例数据(注意:示例已被简化):

tabBank 交易支付

| parent | payment_document | allocated_amount |
------------------------------------------------
| doc1   | Journal Entry    | 10.00            |
| doc1   | Journal Entry20  | 4000.00          |
| doc2   | Journal Entry    | 20.00            |
| doc2   | Journal Entry20  | 5000.00          |
| doc3   | Journal Entry    | 30.00            |
| doc3   | Journal Entry20  | 6000.00          |

tabBank 交易

| name | date       | docstatus |
---------------------------------
| doc1 | 2022-01-01 | 1         |
| doc2 | 2022-02-01 | 1         |
| doc3 | 2022-03-01 | 1         |

要求的结果: (60.00, doc3)

mariadb 版本:10.2.27

我们可以尝试使用ROW_NUMBER&SUMwindow函数来制作

ROW_NUMBER 通过 bt.date desc

得到最后一行的名字

OVER 子句对于 window 函数是必不可少的,它根据一组记录执行计算,PARTITION BY 定义行被划分到的组。

更多细节我们可以看到Window Function Concepts and Syntax

SELECT total_allocated_amount,name
FROM (
    SELECT
        SUM(btp.allocated_amount) OVER() total_allocated_amount,
        ROW_NUMBER() OVER(ORDER BY bt.date desc) rn,
        bt.name
    FROM
        `tabBank Transaction Payments` as btp
    LEFT JOIN
        `tabBank Transaction` bt ON bt.name=btp.parent
    WHERE
        btp.payment_document = 'Journal Entry'
    AND
        bt.docstatus = 1
) t1
WHERE rn = 1

sqlfiddle

感谢 D-Shih 对 window 功能的建议和介绍,我不知道这些功能的存在。我简化并以这个结束。

对于其他由于分区需要多个结果行的场景,需要ROW_NUMBER()

SELECT *
FROM (
    SELECT
        SUM(btp.allocated_amount) OVER() total_allocated_amount,
        FIRST_VALUE(bt.name) OVER(ORDER BY bt.date desc) latest_name
    FROM
        `tabBank Transaction Payments` as btp
    LEFT JOIN
        `tabBank Transaction` bt ON bt.name=btp.parent
    WHERE
        btp.payment_document = 'Journal Entry'
    AND
        bt.docstatus = 1
) t1
LIMIT 1