【问题标题】:MySQL cumulative sum grouped by date but exclude after certain dateMySQL 累积总和按日期分组,但在特定日期后排除
【发布时间】:2020-04-03 19:12:23
【问题描述】:

我有一个涉及日期的查询非常接近完成,但我无法完全了解最后一部分。表格列是:

purchased TINYINT
purchased_date DATE
expired TINYINT
expiration_date DATE

我正在运行的查询是这样的:

SELECT 
    e_date,
    num_interactions,
    @runningTotal := @runningTotal + totals.num_interactions AS runningTotal
FROM
(SELECT 
    DATE(purchase_date) AS e_date,
    COUNT(*) AS num_interactions
FROM domain_names AS d
WHERE purchased = 1
AND purchase_date != "0000-00-00"
GROUP BY DATE(d.purchase_date)) totals
ORDER BY e_date;

它运作良好,但我需要最后一次调整。我需要在 e_date 之后从运行总数中排除/减去已过期的名称(基于 expiration date)。

换句话说,如果运行总数不应计算过期日期之后的域。非常感谢您在这里的任何建议。这是我在这里的第一篇文章,所以希望我已经解释清楚了。

编辑: 我已经组装了一个 MCRE:

CREATE TABLE IF NOT EXISTS `domain_names` (
  `id` bigint(20) NOT NULL AUTO_INCREMENT,
  `name` varchar(255) DEFAULT NULL,
  `purchased` tinyint(1) DEFAULT NULL,
  `purchase_date` date DEFAULT NULL,
  `expired` tinyint(1) DEFAULT NULL,
  `expiration_date` date DEFAULT NULL,
  PRIMARY KEY (`id`),
  KEY `index_domain_names_on_id` (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8;

INSERT INTO `domain_names` (`id`, `name`, `purchased`, `purchase_date`, `expired`, `expiration_date`) VALUES
  ('1', 'example1.com', '1', '2019-01-12', NULL, '2019-08-12'),
  ('2', 'example2.com', '1', '2019-01-12', NULL, '2020-10-12'),
  ('3', 'example3.com', '1', '2019-01-12', '1', '2019-10-12'),
  ('4', 'example4.com', '1', '2019-10-12', NULL, '2020-10-12'),
  ('5', 'example2.com', '1', '2019-03-19', NULL, '2020-03-19'),
  ('6', 'example3.com', '1', '2019-08-19', NULL, '2020-08-10'),
  ('7', 'example4.com', '1', '2019-11-28', NULL, '2020-10-12');

http://sqlfiddle.com/#!9/2d9f71/1/1

【问题讨论】:

标签: mysql date group-by cumulative-sum


【解决方案1】:

这是一种不依赖于变量和子查询的不同方法

SELECT 
    DATE(d.purchase_date),
    COUNT(DISTINCT d.id) AS num_interactions,
    COUNT(DISTINCT c.id) AS cumulative_sum_not_expired
FROM domain_names AS d
LEFT JOIN domain_names AS c ON (DATE(c.purchase_date) <= DATE(d.purchase_date)
                                AND c.purchased = 1
                                AND c.purchase_date != 0
                                AND c.expiration_date >= CURDATE())
WHERE d.purchased = 1
      AND d.purchase_date != 0
GROUP BY 1
ORDER BY 1;

http://sqlfiddle.com/#!9/2d9f71/36/0

您可以在此处调整排除: c.expiration_date &gt;= CURDATE()

【讨论】:

  • 非常感谢@zimza。这非常有效!我通过添加OR c.expiration_date is null 做了一个小改动,以说明没有到期日期的行。再次感谢您!
【解决方案2】:

如果您需要排除过期域,那么您应该将 where 子句 expiration_date &gt; CURDATE() 添加到 couning 子查询或仅计算未过期域 COUNT(case when expiration_date &gt; CURDATE() then 1 end)...

SET @runningTotal := 0;
SET @runningTotalNE := 0;
SELECT 
    e_date,
    num_interactions,
    @runningTotal := @runningTotal + totals.num_interactions AS runningTotal,
    @runningTotalNE := @runningTotalNE + totals.notexpired AS runningTotalNotExpired
FROM
    (SELECT 
     purchase_date AS e_date,
     COUNT(*) AS num_interactions,
     COUNT(case when expiration_date > CURDATE() then 1 end) AS notexpired
     FROM domain_names AS d
     WHERE purchased = 1
     /*AND expiration_date > CURDATE()*/
     AND purchase_date != "0000-00-00"
     GROUP BY d.purchase_date) totals
     ORDER BY e_date

【讨论】:

  • 感谢@AdamSilenko 的回复。我的意思是运行总数中的那一行,只计算那个e_date上没有过期的域。
猜你喜欢
  • 2014-04-12
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-06-09
  • 2021-11-17
  • 1970-01-01
相关资源
最近更新 更多