从单个 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
&SUM
window函数来制作
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
感谢 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
有没有办法 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
&SUM
window函数来制作
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
感谢 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