Как сформировать это предложение WHERE в MySQL? - PullRequest
0 голосов
/ 11 мая 2018

Оказывается, у меня есть таблица данных, которая выглядит примерно так:

┌─────────────────┬────────────────┬─────────────────────────┐
│ 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) и заканчивается в августе (8).Например, третий rown не должен быть включен в результаты, так как 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 в противном случае.

Конечно, этот код не имеет смысла.Мне нужно знать:

  • как конвертировать между типами данных,
  • , как объединять атрибуты и константы.

Возможно ли это?Есть идеи?

1 Ответ

0 голосов
/ 11 мая 2018

Сначала преобразуйте 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

Теперь вы можете работать с created_at, start_period и end_period, используя сравнение between.

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;

Поскольку информация об учебном году будет дублироваться много раз, второй редизайн будет состоять в том, чтобы перенести информацию об учебном году в свою собственную таблицу и сослаться на нее как на внешний ключ.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...