简体   繁体   English

MySql:三个级别的相关表上的 SUM/COUNT

[英]MySql : SUM/COUNT on three level of related tables

I'm trying to do some stats on my tables and I need your help.我正在尝试在我的桌子上做一些统计,我需要你的帮助。 I have three tables : "sessions", "subscriptions" and "invoices"我有三个表:“会话”、“订阅”和“发票”

So a "session" can have multiple "subscribers", and each subscriber can have multiple invoices.所以一个“会话”可以有多个“订阅者”,每个订阅者可以有多个发票。 The goal here is to show a summarize in one query :这里的目标是在一个查询中显示摘要:

+-----------+--------------------+--------------------+---------------------+
|  Session  | Subscription count | Estimated cost sum | Invoices amount sum |
+-----------+--------------------+--------------------+---------------------+
| Session 1 |                  2 |                 15 |                  16 |
| Session 2 |                  1 |                 20 |                  20 |
| Session 3 |                  2 |                 50 |                  40 |
+-----------+--------------------+--------------------+---------------------+

You can find corresponding SQL structure and data :您可以找到相应的 SQL 结构和数据:

SET NAMES utf8;
SET foreign_key_checks = 0;
SET sql_mode = 'NO_AUTO_VALUE_ON_ZERO';

DROP TABLE IF EXISTS `stack_invoices`;
CREATE TABLE `stack_invoices` (
  `id` int(10) unsigned NOT NULL AUTO_INCREMENT,
  `inscription_id` int(10) unsigned NOT NULL,
  `amount` double NOT NULL,
  PRIMARY KEY (`id`),
  KEY `inscription_id` (`inscription_id`),
  CONSTRAINT `stack_invoices_ibfk_1` FOREIGN KEY (`inscription_id`) REFERENCES `stack_subscriptions` (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

INSERT INTO `stack_invoices` (`id`, `inscription_id`, `amount`) VALUES
(1, 1,  5),
(2, 1,  6),
(3, 2,  5),
(4, 3,  10),
(5, 3,  5),
(6, 3,  5),
(7, 4,  40);

DROP TABLE IF EXISTS `stack_sessions`;
CREATE TABLE `stack_sessions` (
  `id` int(10) unsigned NOT NULL AUTO_INCREMENT,
  `title` varchar(10) NOT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

INSERT INTO `stack_sessions` (`id`, `title`) VALUES
(1, 'Session 1'),
(2, 'Session 2'),
(3, 'Session 3');

DROP TABLE IF EXISTS `stack_subscriptions`;
CREATE TABLE `stack_subscriptions` (
  `id` int(10) unsigned NOT NULL AUTO_INCREMENT,
  `name` varchar(15) NOT NULL,
  `estimated_cost` double DEFAULT NULL,
  `session_id` int(10) unsigned NOT NULL,
  PRIMARY KEY (`id`),
  KEY `session_id` (`session_id`),
  CONSTRAINT `stack_subscriptions_ibfk_1` FOREIGN KEY (`session_id`) REFERENCES `stack_sessions` (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

INSERT INTO `stack_subscriptions` (`id`, `name`, `estimated_cost`, `session_id`) VALUES
(1, 'Mister A', 10, 1),
(2, 'Mister B', 5,  1),
(3, 'Mister C', 20, 2),
(4, 'Mister D', 50, 3),
(5, 'Mister E', NULL,   3);

Here are my attempts : Showing estimated cost sum :这是我的尝试: 显示估计成本总和:

SELECT
  stack_sessions.title as session,
  SUM(stack_subscriptions.estimated_cost) as estimated_cost_sum
FROM stack_sessions
LEFT JOIN 
  stack_subscriptions 
ON
  stack_subscriptions.session_id = stack_sessions.id
GROUP BY
  stack_sessions.id

It is ok.没关系。

Adding subscription count :添加订阅计数:

SELECT
  stack_sessions.title as session,
  (
    SELECT 
      COUNT(subscriptions1.id) 
    FROM 
      stack_subscriptions subscriptions1 
    WHERE 
      subscriptions1.session_id = stack_sessions.id
  ) as subscriptions_count,
  SUM(stack_subscriptions.estimated_cost) as estimated_cost_sum
FROM stack_sessions
LEFT JOIN 
  stack_subscriptions 
ON
  stack_subscriptions.session_id = stack_sessions.id
GROUP BY
  stack_sessions.id

It is ok.没关系。

But when I want to show the sum of all invoice group by the session... It no longer work :但是当我想按会话显示所有发票组的总和时......它不再起作用:

SELECT
  stack_sessions.title as session,
  (
    SELECT 
      COUNT(subscriptions1.id) 
    FROM 
      stack_subscriptions subscriptions1 
    WHERE 
      subscriptions1.session_id = stack_sessions.id
  ) as subscriptions_count,
  SUM(stack_subscriptions.estimated_cost) as estimated_cost_sum,
  SUM(stack_invoices.amount) as invoices_amount_sum
FROM stack_sessions
LEFT JOIN 
  stack_subscriptions 
ON
  stack_subscriptions.session_id = stack_sessions.id
LEFT JOIN
  stack_invoices
ON
  stack_invoices.inscription_id = stack_subscriptions.id
GROUP BY
  stack_sessions.id

With this attempt, data are correct for subscriptions count and invoices amount sum but not for estimated cost sum .通过此尝试,订阅计数发票金额总和的数据是正确的,但估计成本总和的数据不正确。

I tried another way :我尝试了另一种方式:

SELECT
  stack_sessions.title as session,
  (
    SELECT 
      COUNT(subscriptions1.id) 
    FROM 
      stack_subscriptions subscriptions1 
    WHERE 
      subscriptions1.session_id = stack_sessions.id
  ) as subscriptions_count,
  SUM(stack_subscriptions.estimated_cost) as estimated_cost_sum,
  (
    SELECT
      SUM(stack_invoices.amount) as invoices_amount_sum
    FROM 
      stack_invoices
    WHERE
      stack_invoices.inscription_id = stack_subscriptions.id
  )
FROM stack_sessions
LEFT JOIN 
  stack_subscriptions 
ON
  stack_subscriptions.session_id = stack_sessions.id
GROUP BY
  stack_sessions.id

But MySql ask me to group by correctly and I can't find the good columns to group by.但是 MySql 要求我正确分组,我找不到要分组的好列。

I don't know if it is possible in one query ?我不知道在一个查询中是否可能? Perhaps there is some SQL notion that I miss...也许有一些我想念的 SQL 概念......

Thanks for your help,谢谢你的帮助,

I think one of the solutions might be this:我认为其中一种解决方案可能是这样的:

SELECT
  stack_sessions.title AS session,
  ANY_VALUE(stack_subscription_summary.subscriptions_count) AS subscriptions_count,
  ANY_VALUE(stack_subscription_summary.estimated_cost_sum) AS estimated_cost_sum,
  SUM(stack_invoices.amount) AS invoices_amount_sum
FROM
    stack_sessions
    LEFT JOIN (
        SELECT
            session_id AS session_id,
            SUM(estimated_price) AS estimated_cost_sum,
            COUNT(id) AS subscriptions_count
        FROM
            stack_subscriptions
        GROUP BY
            session_id
    ) AS stack_subscription_summary ON
        stack_sessions.id = stack_subscription_summary.session_id
    LEFT JOIN stack_subscriptions ON
        stack_subscriptions.session_id = stack_sessions.id
    LEFT JOIN stack_invoices ON
        stack_invoices.inscription_id = stack_subscriptions.id
GROUP BY
  stack_sessions.id

How does it solve your issue?它如何解决您的问题?

Your code stopped working because you were doing SUM of nondistinct rows - meaning you added a value of subscription more then once if it had more invoices.您的代码停止工作,因为您正在对非不同行进行SUM - 这意味着如果有更多发票,您将多次添加订阅值。

That means you need to group some of your data in a subquery.这意味着您需要在子查询中对某些数据进行分组。 I'm showing this on grouping subscription data (therefore getting their summaries), but the probably more elegant way (and probably faster) would be to group invoice data like this:我在分组订阅数据(因此得到他们的摘要)时展示了这一点,但可能更优雅的方式(并且可能更快)是像这样对发票数据进行分组:

SELECT
  stack_sessions.title AS SESSION,
  COUNT(stack_subscriptions.id) AS subscriptions_count,
  SUM(stack_subscriptions.estimated_cost) AS estimated_cost_sum,
  SUM(stack_invoices_summary.amount) AS invoices_amount_sum
FROM
  stack_sessions
  LEFT JOIN stack_subscriptions ON
    stack_subscriptions.session_id = stack_sessions.id
  LEFT JOIN (
    SELECT  
      inscription_id AS inscription_id,
      SUM(amount) AS amount
    FROM
      stack_invoices
    GROUP BY
      inscription_id
  ) AS stack_invoices_summary ON
    stack_invoices_summary.inscription_id = stack_subscriptions.id
GROUP BY
  stack_sessions.id

I haven't tested this on your data, so let me know if it helps!我还没有在你的数据上测试过这个,所以如果有帮助,请告诉我!

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM