我有一张这样的表:
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
因此,对于第1个月和第2个,ID 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");
答案 0 :(得分:1)
如果我理解正确,您需要一个表格,其中包含每个开始日期和结束日期之间的日期(年 - 月)。
没有简单的select
语句可以为您提供此功能,但您可以创建一个程序来执行此操作。您需要创建一个临时表,用您需要的值填充它,然后输出结果。
这是我提出的解决方案(考虑永久性表格):
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
语句是输出结果的语句。您可以在每次需要时执行它。
希望这有帮助
答案 1 :(得分:0)
我找到了另一种方法,但这不是一个简单的select
语句,我认为它很容易出错,但无论如何我会把它放在这里:
select mytable.id, month, year
from mytable,
(select month, year
from
(select 1 as month
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 a,
(select year(start) as year from mytable
union select year(end) as year from mytable) as b) as a
where cast(concat_ws('-', a.year, a.month, day(mytable.start)) as date)
between date(mytable.start) and date(mytable.end)
order by mytable.id, year, month;
查看此其他SQL fiddle。
答案 2 :(得分:0)
我知道我参加晚会很晚,但是我需要一个好的解决方案,而排序不适用于我的数据库版本。
我从https://stackoverflow.com/a/14813173/1707323开始,进行了一些更改以使其可以在本OP中使用。
SELECT
DATE_FORMAT(m1, '%c') AS month_single,
DATE_FORMAT(m1, '%Y') AS this_year
FROM
(
SELECT
'2017-08-15' +INTERVAL m MONTH AS m1
FROM
(
SELECT
@rownum:=@rownum+1 AS m
from
(SELECT 1 UNION SELECT 2 UNION SELECT 3 UNION SELECT 4) t1,
(SELECT 1 UNION SELECT 2 UNION SELECT 3 UNION SELECT 4) t2,
(SELECT 1 UNION SELECT 2 UNION SELECT 3 UNION SELECT 4) t3,
(SELECT 1 UNION SELECT 2 UNION SELECT 3 UNION SELECT 4) t4,
(SELECT @rownum:=-1) t0
) d1
) d2
WHERE
m1<='2020-03-23'
ORDER BY m1
这将获得这两个日期之间的所有月份。请注意,开始日期在第二个select子句中,结束日期在最后的where子句中。这也将包括开始月份和结束月份。可以轻松地对其进行修改,以排除一些额外的+/-间隔的开始和结束月份。