事实证明我有一个类似这样的数据表:
┌─────────────────┬────────────────┬─────────────────────────┐
│ month (integer) │ year (integer) │ academic year (varchar) │
├─────────────────┼────────────────┼─────────────────────────┤
│ 1 │ 2018 │ 2017-2018 │
│ 12 │ 2018 │ 2017-2018 │
│ 3 │ 2019 │ 2018-2019 │
│ 3 │ 2019 │ 2015-2016 │
│ 8 │ 2019 │ 2018-2019 │
└─────────────────┴────────────────┴─────────────────────────┘
请注意不同的数据类型。
我的目标是获取行,使得月份和年份形成属于同一行中学年的日期。学年开始于9月(9)并结束于八月(8)。例如,第三轮不应包括在结果中,因为12/2018不属于2017-2018而是2018-2019。
我的WHERE
子句应该是这样的:
CONVERT(varchar(10), year-1) + '-' + CONVERT(varchar(10), year) = academic_year
如果月份小于9,CONVERT(varchar(10), year) + '-' + CONVERT(varchar(10), year+1) = academic_year
否则。当然这段代码没有意义。我需要知道:
有可能吗?有什么想法吗?
答案 0 :(得分:1)
首先,将month
和year
转换为实际的date
。有很多方法可以对您的数据执行此操作。使用concat
将month
和year
放入MySQL识别为date
的格式中。
date( concat(year,"-",month,"-",1) ) as created_at;
这会将year
和month
转换为从月初开始的单个日期。
然后将academic_year
拆分为两个别名列。我们可以利用格式始终YYYY-YYYY
(您可以使用where academic_year not rlike '^[0-9]{4}-[0-9]{4}$'
验证此格式)并使用left
和right
来获取第一个和最后4个字符。
left(academic_year, 4), right(academic_year, 4)
将这些转换为学年开始和结束的日期。
date( concat(left(academic_year, 4),"-","09","-","01") ) as start_period
date( concat(right(academic_year, 4),"-","08","-","31") ) as end_period
现在,您可以使用between
比较与created_at
,start_period
和end_period
合作。
where created_at between start_period and end_period
把它们放在一起......
select
date( concat(year,"-",month,"-",1) ) as created_at,
date( concat(left(academic_year, 4),"-","09","-","01") ) as start_period,
date( concat(right(academic_year, 4),"-","08","-","31") ) as end_period
from stuff
where created_at between start_period, end_period;
请注意,在完成转换为正确date
类型的工作后,查询变得简单。而不是针对您的特殊需求进行临时解析,最好将其标准化为真正的date
类型并使用内置的MySQL日期函数。
如果可能的话,您应该将架构更改为直接存储为date
类型。它不仅可以使事情变得更简单,而且更快,因为日期列可以被索引以便快速搜索。即使你不能做到这一点,看看如何存储这样的数据也是件好事。
保留旧列以便向后兼容,如果必须,只需添加新列。
add column stuff created_at date not null;
add column stuff academic_year_start date not null;
add column stuff academic_year_end date not null;
填充新列。
update stuff
set created_at = date( concat(year,"-",month,"-",1) ),
academic_year_start = date( concat(left(academic_year, 4),"-","09","-","01") ),
academic_year_end = date( concat(right(academic_year, 4),"-","08","-","31") ) as end_period
并在其上加上索引。
create index stuff_created_at on stuff (created_at);
create index academic_year on stuff (academic_year_start, academic_year_end);
一旦完成了您的查询,以及类似的任何内容,就变得非常简单且非常快。
select *
from stuff
where created_at between academic_year_start and academic_year_end;
因为有关学年的信息会多次重复,所以第二次重新设计是将学年信息转移到自己的表格中,并将其称为外键。
答案 1 :(得分:0)
我相信这是你正在寻找的。这适用于SQL Server。
WHERE
(month < 9 AND CONVERT(VARCHAR(4), year-1)+'-'+CONVERT(VARCHAR(4), year) = academic_year)
OR (month >= 9 AND CONVERT(VARCHAR(4), year)+'-'+CONVERT(VARCHAR(4), year+1) = academic_year)