MYSQL : How to select every YEAR_MONTH between two dates?

标签 mysql

我想做什么:

我有一个这样的表:

TABLE mytable
- ID (INT)
- START (DATETIME)
- END (DATETIME)

假设我有这些行:

| ID  |         START       |          END        |
|--------------------------------------------------
|  1  | 2014-01-02 00:00:00 | 2014-12-02 00:00:00 | => month between : 12
|  2  | 2014-01-03 00:00:00 | 2015-02-03 00:00:00 | => month between : 14

注意:“月份”包括开始月份和结束月份

对于 START 和 END 之间的每个 YEAR_MONTH,我想显示如下行:

ID  |  MONTH  |  YEAR
---------------------
1   |    1    |  2014
1   |    2    |  2014
1   |    3    |  2014
1   |    4    |  2014
1   |    5    |  2014
1   |    6    |  2014
1   |    7    |  2014
1   |    8    |  2014
1   |    9    |  2014
1   |    10   |  2014
1   |    11   |  2014
1   |    12   |  2014
2   |    1    |  2014
2   |    2    |  2014
2   |    3    |  2014
2   |    4    |  2014
2   |    5    |  2014
2   |    6    |  2014
2   |    7    |  2014
2   |    8    |  2014
2   |    9    |  2014
2   |    10   |  2014
2   |    11   |  2014
2   |    12   |  2014
2   |    1    |  2015
2   |    2    |  2015

因此 ID 1 有 12 条记录,ID 2 有 14 条记录。

当月份数 > 12 时,我有点卡住了

我在哪里:

我正在这样做:

SELECT mytable.id,
months.id as month,
YEAR(start) as year
FROM mytable
/* Join on a list from 1 to 12 */
LEFT JOIN (SELECT 1 as id UNION SELECT 2 UNION SELECT 3 UNION SELECT 4 UNION SELECT 5 UNION SELECT 6 UNION SELECT 7 UNION SELECT 8 UNION SELECT 9 UNION SELECT 10 UNION SELECT 11 UNION SELECT 12)
as months ON months.id BETWEEN MONTH(start) AND MONTH(end) 
order by mytable.id, month, year

因此 ID 2 仅包含第 1 个月和第 2 个月的 2 行:

ID  |  MONTH  |  YEAR
---------------------
1   |   1     |   2014
1   |   2     |   2014
1   |   3     |   2014
1   |   4     |   2014
1   |   5     |   2014
1   |   6     |   2014
1   |   7     |   2014
1   |   8     |   2014
1   |   9     |   2014
1   |   10    |   2014
1   |   11    |   2014
1   |   12    |   2014
2   |   1     |   2014
2   |   2     |   2014

您对这个问题有什么想法或建议吗? 有没有办法提取两个日期之间的每个 YEAR_MONTH ? 谢谢。

帮助者:

这是一个用于创建表并插入提到的 2 行的脚本:

CREATE TABLE mytable (
    id INT PRIMARY KEY auto_increment,
    start DATETIME NOT NULL,
    end DATETIME NOT NULL
);

INSERT INTO mytable (start,end) VALUES 
("2014-01-02 00:00:00","2014-12-02 00:00:00"),
("2014-01-03 00:00:00","2015-02-03 00:00:00");

最佳答案

如果我理解正确,您需要一个表格,其中包含每个开始日期和结束日期之间的日期(年 - 月)。

没有简单的 select 语句可以实现这一点,但您可以创建一个过程来执行此操作。您需要创建一个临时表,用您需要的值填充它,然后输出结果。

这是我建议的解决方案(考虑永久表):

SQL Fiddle

MySQL 5.5.32 架构设置:

CREATE TABLE mytable (
    id INT PRIMARY KEY auto_increment,
    start DATETIME NOT NULL,
    end DATETIME NOT NULL
)//

INSERT INTO mytable (start,end) VALUES 
("2014-01-02 00:00:00","2014-12-02 00:00:00"),
("2014-01-03 00:00:00","2015-02-03 00:00:00")//

create procedure year_month_table()
begin
  -- Declare the variables to fill the years_months table
  declare id int;
  declare start_date, end_date, d date;
  -- Declare the "done" variable for the loop that fills the table,
  -- the cursor to read the data, and the handler to check if the
  -- loop should end.
  declare done int default false;
  declare cur_mytable cursor for
    select * from mytable;
  declare continue handler for not found
    set done = true;
  -- Create the table to hold your data
  create table if not exists years_months (
    row_id int unsigned not null auto_increment primary key,
    id int not null,
    month int,
    year int,
    unique index dedup(id, year, month),
    index idx_id(id),
    index idx_year(year),
    index idx_month(month)
  );
  -- Open the cursor to read the ids and the start and end dates for each one
  open cur_mytable;
  -- Disable the indexes to speed up insertion
  alter table years_months disable keys;
  -- Start the loop
  loop_data: loop
    -- Read the values from your table and store them in the variables
    fetch cur_mytable into id, start_date, end_date;
    -- If you've reached the end of the table, then you must exit the loop
    if done then
      leave loop_data;
    end if;
    -- Initialize the date to fill the table
    set d = start_date;
    while d <= end_date do
      -- Insert the values in your table
      insert ignore into years_months (id, month, year) values (id, month(d), year(d));
      -- Increment the d variable in 1 month
      set d = date_add(d, interval +1 month);
    end while;
  end loop;
  close cur_mytable;
  -- Enable the indexes again
  alter table years_months enable keys;
  -- Show the result
  select * from years_months;
end //

查询 1:

select * from mytable

<强> Results :

| ID |                          START |                             END |
|----|--------------------------------|---------------------------------|
|  1 | January, 02 2014 00:00:00+0000 | December, 02 2014 00:00:00+0000 |
|  2 | January, 03 2014 00:00:00+0000 | February, 03 2015 00:00:00+0000 |

查询 2:

call year_month_table()

<强> Results :

| ROW_ID | ID | MONTH | YEAR |
|--------|----|-------|------|
|      1 |  1 |     1 | 2014 |
|      2 |  1 |     2 | 2014 |
|      3 |  1 |     3 | 2014 |
|      4 |  1 |     4 | 2014 |
|      5 |  1 |     5 | 2014 |
|      6 |  1 |     6 | 2014 |
|      7 |  1 |     7 | 2014 |
|      8 |  1 |     8 | 2014 |
|      9 |  1 |     9 | 2014 |
|     10 |  1 |    10 | 2014 |
|     11 |  1 |    11 | 2014 |
|     12 |  1 |    12 | 2014 |
|     13 |  2 |     1 | 2014 |
|     14 |  2 |     2 | 2014 |
|     15 |  2 |     3 | 2014 |
|     16 |  2 |     4 | 2014 |
|     17 |  2 |     5 | 2014 |
|     18 |  2 |     6 | 2014 |
|     19 |  2 |     7 | 2014 |
|     20 |  2 |     8 | 2014 |
|     21 |  2 |     9 | 2014 |
|     22 |  2 |    10 | 2014 |
|     23 |  2 |    11 | 2014 |
|     24 |  2 |    12 | 2014 |
|     25 |  2 |     1 | 2015 |
|     26 |  2 |     2 | 2015 |

请注意,过程中的最后一个 select 语句是输出结果的语句。您可以在每次需要时执行它。

希望这有帮助

关于MYSQL : How to select every YEAR_MONTH between two dates?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/27969181/

相关文章:

mysql - SQL - 根据另一个列值设置列值

mysql - SQL 查询以获取具有特定属性的行的最后一次近似出现(按时间戳)

php - 导入 CSV 数据时跳过重复值

php - 如何在 MySQL 中上传图片 PHP 和插入路径?

mysql - 数据库数据完整性问题

java - 2 个表格 1 个网络应用程序 我该怎么办

php - 在 PHP 和 MySQL 中生成连续的发票号码(并发)

mysql - 选择所有行并分组关系表,即使没有找到结果

php - 订单完成时写入 SQL 表

php - MySQL 查询有多个 WHERE,有些可能为空