MySQL 跨日期范围求和值

发布于 2024-11-02 10:30:29 字数 1682 浏览 2 评论 0原文

我有一个表,每行包含一个日期和一些任意的数值。我需要对特定但动态的日期间隔的该值求和。

SELECT VERSION();
5.0.51a-24+lenny5

CREATE TABLE IF NOT EXISTS `work_entries` (
  `entry_id` int(10) unsigned NOT NULL auto_increment,
  `employee_id` tinyint(3) unsigned NOT NULL,
  `work_date` date NOT NULL,
  `hour_count` tinyint(3) unsigned NOT NULL,
  PRIMARY KEY  (`entry_id`)
);

INSERT INTO `work_entries` (`entry_id`, `employee_id`, `work_date`, `hour_count`) VALUES
(1, 1, '2011-04-25', 2),
(2, 1, '2011-04-26', 3),
(3, 1, '2011-04-27', 1),
(4, 2, '2011-04-25', 2),
(5, 2, '2011-04-27', 4),
(6, 1, '2011-05-08', 2),
(7, 2, '2011-05-06', 8),
(8, 2, '2011-05-08', 9),
(9, 2, '2011-05-09', 1),
(10, 1, '2011-05-29', 3),
(11, 1, '2011-05-30', 1),
(12, 2, '2011-05-30', 2),
(13, 1, '2011-06-02', 2),
(14, 1, '2011-06-04', 3),
(15, 1, '2011-06-14', 1),
(16, 2, '2011-06-14', 2),
(17, 2, '2011-06-17', 4),
(18, 1, '2011-06-18', 2),
(19, 2, '2011-06-19', 8),
(20, 2, '2011-06-26', 9),
(21, 2, '2011-07-01', 1),
(22, 1, '2011-07-03', 3),
(23, 1, '2011-07-03', 1),
(24, 2, '2011-07-16', 2);

以下查询返回上述数据集的正确输出,并且应该说明我正在尝试执行的操作,但是,我需要根据 work_date 生成年份和月份值。日子(16、15)永远不会改变。具体来说,此查询将生成两行,一行用于指定的时间间隔,另一行用于其余时间,其中每个周期需要一行(对于具有值的所有月份,从 N 月 16 日到 N+1 月 15 日)。

SELECT
 SUM(hour_count) AS res
 FROM `work_entries`
 GROUP BY work_date
 BETWEEN '2011-04-16' AND '2011-05-15';

-- Outputs
res
----
44
32

-- Should give
res
----
32
14
28
 2

另一个可以正常工作但时间间隔错误(第 01-31 天)的示例:

SELECT
 SUM(hour_count) AS res
 FROM `work_entries`
 GROUP BY MONTH(work_date);

-- Outputs
res
---
12
26
31
 7

此外,如果有一种方法可以同时输出起始日期和截止日期,我也希望如此,但这不是很好重要的。

I have a table with each row containing a date and some arbitrary, numeric value. I need to sum this value for a specific but dynamic date interval.

SELECT VERSION();
5.0.51a-24+lenny5

CREATE TABLE IF NOT EXISTS `work_entries` (
  `entry_id` int(10) unsigned NOT NULL auto_increment,
  `employee_id` tinyint(3) unsigned NOT NULL,
  `work_date` date NOT NULL,
  `hour_count` tinyint(3) unsigned NOT NULL,
  PRIMARY KEY  (`entry_id`)
);

INSERT INTO `work_entries` (`entry_id`, `employee_id`, `work_date`, `hour_count`) VALUES
(1, 1, '2011-04-25', 2),
(2, 1, '2011-04-26', 3),
(3, 1, '2011-04-27', 1),
(4, 2, '2011-04-25', 2),
(5, 2, '2011-04-27', 4),
(6, 1, '2011-05-08', 2),
(7, 2, '2011-05-06', 8),
(8, 2, '2011-05-08', 9),
(9, 2, '2011-05-09', 1),
(10, 1, '2011-05-29', 3),
(11, 1, '2011-05-30', 1),
(12, 2, '2011-05-30', 2),
(13, 1, '2011-06-02', 2),
(14, 1, '2011-06-04', 3),
(15, 1, '2011-06-14', 1),
(16, 2, '2011-06-14', 2),
(17, 2, '2011-06-17', 4),
(18, 1, '2011-06-18', 2),
(19, 2, '2011-06-19', 8),
(20, 2, '2011-06-26', 9),
(21, 2, '2011-07-01', 1),
(22, 1, '2011-07-03', 3),
(23, 1, '2011-07-03', 1),
(24, 2, '2011-07-16', 2);

The following query returns the correct output for the above data set and should illustrate what I'm trying to do, however, I need to generate the year and month values based on work_date. The days (16, 15) never change. Specifically, this query will produce two rows, one for the specified interval and one for the rest, where I need one row for each period (16th of month N to 15th of month N+1 for all months with values).

SELECT
 SUM(hour_count) AS res
 FROM `work_entries`
 GROUP BY work_date
 BETWEEN '2011-04-16' AND '2011-05-15';

-- Outputs
res
----
44
32

-- Should give
res
----
32
14
28
 2

An alternative example that works correctly but on the wrong interval (days 01-31):

SELECT
 SUM(hour_count) AS res
 FROM `work_entries`
 GROUP BY MONTH(work_date);

-- Outputs
res
---
12
26
31
 7

Additionally, if there is a way to output the from- and to- dates at the same time I'd like that as well, but that's not very important.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(5

肤浅与狂妄 2024-11-09 10:30:29

迷人的:

SELECT
 SUM(hour_count)
 FROM `work_entries`
 GROUP BY
   YEAR(work_date - INTERVAL 15 DAY),
   MONTH(work_date - INTERVAL 15 DAY);

lovely:

SELECT
 SUM(hour_count)
 FROM `work_entries`
 GROUP BY
   YEAR(work_date - INTERVAL 15 DAY),
   MONTH(work_date - INTERVAL 15 DAY);
仙女 2024-11-09 10:30:29
SELECT
  YEAR(grouping_date) AS year,
  MONTH(grouping_date) AS month,
  SUM(hour_count) AS hour_count_total
FROM (
  SELECT
    work_date,
    hour_count,
    work_date - INTERVAL 15 DAY AS grouping_date
  FROM work_entries
) x
GROUP BY
  YEAR(grouping_date),
  MONTH(grouping_date)
SELECT
  YEAR(grouping_date) AS year,
  MONTH(grouping_date) AS month,
  SUM(hour_count) AS hour_count_total
FROM (
  SELECT
    work_date,
    hour_count,
    work_date - INTERVAL 15 DAY AS grouping_date
  FROM work_entries
) x
GROUP BY
  YEAR(grouping_date),
  MONTH(grouping_date)
疾风者 2024-11-09 10:30:29
SELECT
    YEAR(work_date) AS year,
    MONTH(work_date) AS month,
    case
        when right(work_date,2) between '01' and '15' then 1
        when right(work_date,2) between '16' and '31' then 2
    end 
    as partofmonth,
    SUM(hour_count) AS totalper15period
FROM work_entries
GROUP BY year, month, partofmonth
SELECT
    YEAR(work_date) AS year,
    MONTH(work_date) AS month,
    case
        when right(work_date,2) between '01' and '15' then 1
        when right(work_date,2) between '16' and '31' then 2
    end 
    as partofmonth,
    SUM(hour_count) AS totalper15period
FROM work_entries
GROUP BY year, month, partofmonth
疯狂的代价 2024-11-09 10:30:29

您可以使用另一个表来存储所有期间范围。

create table `periods` (
  `id` int(11) not null auto_increment,
  `start` date default null,
  `end` date default null,
  primary key (`id`)
) engine=myisam auto_increment=4 default charset=latin1;


insert  into `periods`(`id`,`start`,`end`) values (1,'2011-04-16','2011-05-15');
insert  into `periods`(`id`,`start`,`end`) values (2,'2011-05-16','2011-06-15');
insert  into `periods`(`id`,`start`,`end`) values (3,'2011-06-16','2011-07-15');

并与其建立连接

select 
p.start,p.end,
sum(w.hour_count) as total
from periods as p
inner join work_entries as w
on w.work_date between p.start and p.end
group by p.start

+------------+------------+-------+
| start      | end        | total |
+------------+------------+-------+
| 2011-04-16 | 2011-05-15 |    32 |
| 2011-05-16 | 2011-06-15 |     6 |
+------------+------------+-------+
2 rows in set (0.00 sec)

然后您可以在需要时添加 where 子句。

You could use another table where you store all period ranges.

create table `periods` (
  `id` int(11) not null auto_increment,
  `start` date default null,
  `end` date default null,
  primary key (`id`)
) engine=myisam auto_increment=4 default charset=latin1;


insert  into `periods`(`id`,`start`,`end`) values (1,'2011-04-16','2011-05-15');
insert  into `periods`(`id`,`start`,`end`) values (2,'2011-05-16','2011-06-15');
insert  into `periods`(`id`,`start`,`end`) values (3,'2011-06-16','2011-07-15');

and make a join with it

select 
p.start,p.end,
sum(w.hour_count) as total
from periods as p
inner join work_entries as w
on w.work_date between p.start and p.end
group by p.start

+------------+------------+-------+
| start      | end        | total |
+------------+------------+-------+
| 2011-04-16 | 2011-05-15 |    32 |
| 2011-05-16 | 2011-06-15 |     6 |
+------------+------------+-------+
2 rows in set (0.00 sec)

You can then put a where clause when you need it.

↙厌世 2024-11-09 10:30:29

有点hackish,但

SELECT 
  SUM(hour_count),
  STR_TO_DATE(
    CONCAT(
      EXTRACT(YEAR_MONTH FROM work_date),
      '16'
    ),
    '%Y%m%d'
  ) AS startperiod,
  DATE_ADD(
    STR_TO_DATE(
      CONCAT(
        EXTRACT(YEAR_MONTH FROM work_date),
        '15'
      ),
      '%Y%m%d'
    ),
    INTERVAL 1 MONTH
  ) AS endperiod 
FROM
  work_entries 
GROUP BY work_date BETWEEN startperiod 
  AND endperiod;

仔细想想,上面的方法根本行不通。它只会返回两行,具体取决于 work_date 字段是否落在生成的开始/结束时间段内或之外。

基本上,您所需的查询需要一个更像“财政月”而不是日历月的组间隔。

Somewhat hackish, but

SELECT 
  SUM(hour_count),
  STR_TO_DATE(
    CONCAT(
      EXTRACT(YEAR_MONTH FROM work_date),
      '16'
    ),
    '%Y%m%d'
  ) AS startperiod,
  DATE_ADD(
    STR_TO_DATE(
      CONCAT(
        EXTRACT(YEAR_MONTH FROM work_date),
        '15'
      ),
      '%Y%m%d'
    ),
    INTERVAL 1 MONTH
  ) AS endperiod 
FROM
  work_entries 
GROUP BY work_date BETWEEN startperiod 
  AND endperiod;

Thinking about it, the above wouldn't work at all. It'd only ever return two rows, based on if the work_date field falls inside the generated start/end periods, or outside.

Basically your desired query requires a group interval that's more of a "fiscal month" than a calendar month.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文