如何在MySQL中形成这个WHERE子句?

时间:2018-05-11 18:14:20

标签: mysql sql

事实证明我有一个类似这样的数据表:

┌─────────────────┬────────────────┬─────────────────────────┐
│ 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否则。

当然这段代码没有意义。我需要知道:

  • 如何在数据类型之间进行转换,
  • 如何连接属性和常量。

有可能吗?有什么想法吗?

2 个答案:

答案 0 :(得分:1)

首先,将monthyear转换为实际的date。有很多方法可以对您的数据执行此操作。使用concatmonthyear放入MySQL识别为date的格式中。

date( concat(year,"-",month,"-",1) ) as created_at;

这会将yearmonth转换为从月初开始的单个日期。

然后将academic_year拆分为两个别名列。我们可以利用格式始终YYYY-YYYY(您可以使用where academic_year not rlike '^[0-9]{4}-[0-9]{4}$'验证此格式)并使用leftright来获取第一个和最后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_atstart_periodend_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)