MySQL自定义输出的一些值

时间:2018-11-02 21:08:18

标签: mysql sql database subquery

我有两个无法解决的问题。

  1. 显示来自不同表的两个单元格的值之间的差异
  2. 根据子查询中返回的行数和/或单元格的值显示自定义输出

在这种特定情况下,我需要在单个MySQL查询中将多个表与自定义输出结合并合并。

去除非必要列并包含假数据的表是:

transactions
+----+-------------+------------+--------+
| id | vendor_id   | payment_id | amount |
+----+-------------+------------+--------+
| 1  | 12          | 45         | 25     |
| 2  | 13          | 46         | 50     |
| 3  | 14          | 47         | 50     |
| 4  | 15          | 48         | 50     |
+----+-------------+------------+--------+

vendors
+-----+-------------+
| id  | vendor_code |
+-----+-------------+
| 12  | abc123      |
| 13  | efg321      |
| 14  | hjk456      |
| 15  | fed789      |
+-----+-------------+

payments
+-----+-------+--------+
| id  | order | amount |
+-----+-------+--------+
| 45  | 0032  | 25     |
| 46  | 0063  | 50     |
| 47  | 0073  | 50     |
| 48  | 0087  | 50     |
+-----+-------+--------+

refunds
+----+----------------+--------+
| id | transaction_id | amount |
+----+----------------+--------+
| 65 | 2              | 10     |
+----+----------------+--------+

properties
+-----+----------+
| id  | group_id |
+-----+----------+
| 100 | 222      |
| 200 | 333      |
+-----+----------+

vendor_properties
+----+-------------+------------+
| id | property_id | vendor_id  |
+----+-------------+------------+
| 1  | 100         | 12         |
| 2  | 200         | 12         |
| 3  | 100         | 13         |
| 4  | 200         | 14         |
+----+-------------+------------+

groups
+-----+---------+
| id  | name    |
+-----+---------+
| 222 | groupA  |
| 333 | groupB  |
+-----+---------+

存在以下关系:

transactions.payment_id -> payments.id
transactions.vendor_id -> vendors.id
payments.vendor_id -> vendors.id
refunds.transaction_id -> transactions.id
properties.property_group_id -> groups.id
vendor_properties.property_id -> properties.id
vendor_properties.vendor_id -> vendors.id

我当前的SQL查询是:

SELECT
    `transactions`.`id` AS DB_transID,
    `transactions`.`vendor_id` AS DB_vendID,
    `vendors`.`vendor_code` AS "VendorCode",
    `payments`.`order` AS "Order",
    `transactions`.`amount` AS "Amount"
    `refunds`.`amount` AS "Refunded",
    `groups`.`name` AS "Group"
FROM
    `transactions`
LEFT JOIN
    `payments` ON `payments`.`id` = `transactions`.`payment_id`
LEFT JOIN
    `vendors` ON `vendors`.`id` = `transactions`.`vendor_id`
LEFT JOIN
    `refunds` ON `refunds`.`transaction_id` = `transactions`.`id`
LEFT JOIN
    `groups` ON `groups`.`id` IN
    ( 
        SELECT `group_id` FROM `properties` WHERE `id` IN
        ( 
            SELECT `property_id` FROM `vendor_properties`
            WHERE `vendor_id` = @refID
        )
     );

输出为:

+------------+-----------+------------+-------+--------+----------+--------+
| DB_transID | DB_vendID | VendorCode | Order | Amount | Refunded | Group  |
+------------+-----------+------------+-------+--------+----------+--------+
| 1          | 12        | abc123     | 0032  | 25     | NULL     | groupA |
| 1          | 12        | abc123     | 0032  | 25     | NULL     | groupB |
| 2          | 13        | efg321     | 0063  | 50     | 10       | groupA |
| 3          | 14        | hjk456     | 0073  | 50     | NULL     | groupB |
| 4          | 15        | fed789     | 0087  | 50     | NULL     | NULL   |
+------------+-----------+------------+-------+--------+----------+--------+

我想做的是:

  1. 添加一列“净额”,其中包含(金额-已退款)的值
  2. 当一个事务具有与事务1相同的多个Group时,与其创建两行,不如在Group列中使用“ groupA,groupB”创建一行。当Group为NULL时,该值应为“ None”。组名称列表应删除重复数据。例如,如果groupA出现在三个事务中,而group B出现在两个事务中,则输出将为“ groupA,groupB”。
  3. 当退款为NULL时,值应为“ 0”

因此所需的输出将是:

+------------+-----------+------------+-------+--------+----------+-----+----------------+
| DB_transID | DB_vendID | VendorCode | Order | Amount | Refunded | Net | Group          |
+------------+-----------+------------+-------+--------+----------+-----+----------------+
| 1          | 12        | abc123     | 0032  | 25     | 0        | 25  | groupA, groupB |
| 2          | 13        | efg321     | 0063  | 50     | 10       | 40  | groupA         |
| 3          | 14        | hjk456     | 0073  | 50     | 0        | 50  | groupB         |
| 4          | 15        | fed789     | 0087  | 50     | 0        | 50  | None           |
+------------+-----------+------------+-------+--------+----------+-----+----------------+

在现实生活中,大多数表中都有数千行。作为一个额外的问题,告诉我为什么即使有时数据应该有一个值,有时我仍会为Group获得NULL?

欢迎对该查询进行任何其他改进!

1 个答案:

答案 0 :(得分:1)

这是我实现您目标的第一种方法,如果发现任何改进,我会进行更新:

SELECT
    t.id AS DB_transID,
    t.vendor_id AS DB_vendID,
    t.amount AS Amount,
    v.vendor_code AS VendorCode,
    p.order AS "Order",
    IFNULL(r.amount, 0) AS Refunded,
    IFNULL(t.amount, 0) - IFNULL(r.amount, 0) AS Net,
    IFNULL((
     SELECT GROUP_CONCAT(DISTINCT g.name SEPARATOR ', ')
     FROM vendor_properties vp
     LEFT JOIN properties pr ON pr.id = vp.property_id
     LEFT JOIN groups g ON g.id = pr.group_id
     WHERE vp.vendor_id = t.vendor_id
     GROUP BY vp.vendor_id
    ), "None") AS "Groups"
FROM
    transactions t
LEFT JOIN
     payments p ON p.id = t.payment_id
LEFT JOIN
     vendors v ON v.id = t.vendor_id
LEFT JOIN
     refunds r ON r.transaction_id = t.id;

对此上一个查询进行了改进,如果您的某些外键不允许使用NULL值,则可以使用LEFT JOIN完成相关表之间的INNER JOIN

SELECT
    t.id AS DB_transID,
    ANY_VALUE(t.vendor_id) AS DB_vendID,
    ANY_VALUE(t.amount) AS Amount,
    ANY_VALUE(v.vendor_code) AS VendorCode,
    ANY_VALUE(p.order) AS "Order",
    IFNULL(ANY_VALUE(r.amount), 0) AS Refunded,
    IFNULL(ANY_VALUE(t.amount), 0) - IFNULL(ANY_VALUE(r.amount), 0) AS Net,
    IFNULL(GROUP_CONCAT(DISTINCT g.name SEPARATOR ', '), "None") AS "Group"
FROM
    transactions t
LEFT JOIN
    payments p ON p.id = t.payment_id
LEFT JOIN
    vendors v ON v.id = t.vendor_id
LEFT JOIN
    refunds r ON r.transaction_id = t.id
LEFT JOIN
    vendor_properties vp ON vp.vendor_id = t.vendor_id
LEFT JOIN
    properties pr ON pr.id = vp.property_id
LEFT JOIN
    groups g ON g.id = pr.group_id
GROUP BY
    t.id

希望这对您有所帮助,您可以在此处使用工作示例:

DB-Fiddle