Хранение диапазона месяцев в таблице SQL - PullRequest
0 голосов
/ 06 мая 2020

Я новичок в SQL, изучаю его около 1-2 недель, и я застрял на том, как хранить что-то вроде диапазона значений, которые могут быть где-то между 1 и 6 различными диапазонами.

Например, я пытаюсь создать таблицу, в которой хранятся fi sh и время, в которое каждый fi sh доступен в течение года (на основе игры Animal Crossing). Каждый fi sh имеет определенный набор месяцев, в которые они доступны. Например, синий марлин может быть доступен для ловли в период с января по март, а затем, например, с июня по июль (произвольный пример, вероятно, неверный). Как я могу сохранить это в базе данных SQL, когда потенциально может быть несколько диапазонов, в которых доступен fi sh?

Это то, что я написал до сих пор, но этого было бы недостаточно для Голубого Марлина.

CREATE TABLE fish (
  id INTEGER PRIMARY KEY,
  name TEXT,
  start_month INT,
  end_month INT
);

Один из вариантов - создать 6 разных полей начала и конца, в худшем случае, когда каждый диапазон составляет 1 месяц, с промежутком в 1 месяц (я считаю, что это наихудший case), либо сделать поле на все 12 месяцев. Но это звучит неэффективно и многословно.

Как я мог это сделать? Было бы неплохо иметь возможность сделать запрос, чтобы проверить все fi sh, доступные, например, в мае.

Ответы [ 4 ]

0 голосов
/ 06 мая 2020

У вас всего 12 месяцев. Итак, имейте две таблицы, одну для fi sh и одну для каждого месяца, когда доступен fi sh:

create table fish (
    id int primary key,
    name text
);

create table fishmonths (
    fish_id int references fish(id),
    month int check (month between 1 and 12)
);

Это решает ваш конкретный c вопрос. Мне кажется, что fi sh не живут своей жизнью по григорианскому календарю, поэтому не вся доступность будет на границах месяца. Для более общего решения вам, вероятно, следует задать новый вопрос с дополнительной информацией о том, что вы пытаетесь представить.

0 голосов
/ 06 мая 2020

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

CREATE TABLE available (
  fish_id INTEGER NOT NULL REFERENCES fish(id),
  start_month INTEGER NOT NULL CHECK (start_month BETWEEN 1 AND 12),
  end_month INTEGER NOT NULL CHECK (end_month BETWEEN 1 AND 12),
  PRIMARY KEY (fish_id, start_month, end_month)
);

См. Упрощенную демонстрацию .

Вы можете получить доступность каждого fi sh с помощью запроса, который объединяет 2 таблицы:

SELECT f.id, f.name, 
       a.start_month, a.end_month 
FROM fish f INNER JOIN available a
on a.fish_id = f.id

Результаты, например:

> id | name        | start_month | end_month
> -: | :---------- | ----------: | --------:
>  1 | Blue Marlin |           1 |         3
>  1 | Blue Marlin |           6 |         7
>  2 | Red Marlin  |           2 |         5
>  2 | Red Marlin  |           8 |         9

Или сгруппированные ( для MySql):

SELECT f.id, f.name,
       GROUP_CONCAT(CONCAT(
         MONTHNAME(STR_TO_DATE(a.start_month, '%m')), 
         '-', 
         MONTHNAME(STR_TO_DATE(a.end_month, '%m'))
       )) availability 
FROM fish f INNER JOIN available a
on a.fish_id = f.id
GROUP BY f.id, f.name

Результаты вроде:

> id | name        | availability                 
> -: | :---------- | :----------------------------
>  1 | Blue Marlin | January-March,June-July      
>  2 | Red Marlin  | February-May,August-September
0 голосов
/ 06 мая 2020

Другой подход - добавить столбец месяцев и использовать побитовый флаг для хранения доступных месяцев.

January = 1,
February = 2,
March = 4,
April = 8,
May = 16,
June = 32,
July = 64,
August = 128,
September = 256,
October = 512,
November = 1024,
December = 2048 

Таблица

CREATE TABLE fish (
id INTEGER PRIMARY KEY,
name TEXT,
months INTEGER 
);

Для магазина Blue Marlin 103 в столбец месяцев (январь, февраль, март, июнь и июль) 1 + 2 + 4 + 32 + 64 = 103.

id | name        | months
1  | Blue Marlin | 103

затем используйте следующий запрос для вывода результатов

select id, name,
 CASE WHEN (months & 1 ) <> 0 THEN 1 ELSE 0 END as January,
 CASE WHEN (months & 2 ) <> 0 THEN 1 ELSE 0 END as February,
 CASE WHEN (months & 4 ) <> 0 THEN 1 ELSE 0 END as March,
 CASE WHEN (months & 8 ) <> 0 THEN 1 ELSE 0 END as April,
 CASE WHEN (months & 16 ) <> 0 THEN 1 ELSE 0 END as May,
 CASE WHEN (months & 32 ) <> 0 THEN 1 ELSE 0 END as June,
 CASE WHEN (months & 64 ) <> 0 THEN 1 ELSE 0 END as July, 
 CASE WHEN (months & 128 ) <> 0 THEN 1 ELSE 0 END as August,
 CASE WHEN (months & 256 ) <> 0 THEN 1 ELSE 0 END as September,
 CASE WHEN (months & 512 ) <> 0 THEN 1 ELSE 0 END as October,
 CASE WHEN (months & 1024 ) <> 0 THEN 1 ELSE 0 END as November,
 CASE WHEN (months & 2048 ) <> 0 THEN 1 ELSE 0 END as December
from fish

Вот так

id | name        | January  | February | March | April | May | June | July | August | September | October | November | December
1  | Blue Marlin | 1        | 1        | 1     | 0     | 0   | 1    | 1    | 0      | 0         | 0       | 0        | 0

Это дает хороший обзор каждого fi sh и месяцев, в которых он доступен, с дополнительным преимуществом, вы можете быстро сканировать конкретный месяц и видеть, какие fi sh доступны .

Вы можете расширить это, изменив операторы case, чтобы они возвращали что-то другое, кроме 1 и 0, если вы предпочитаете или измените запрос для отображения диапазонов месяцев.

Лично, если бы я использовал это для игры, я бы хотел видеть макет месяц за месяцем.

0 голосов
/ 06 мая 2020

Это должно быть сделано с использованием нескольких таблиц. Один будет для другого fi sh данных (имя и что угодно), а другой - специально для месяцев. Диапазоны должны храниться в таблице диапазонов со ссылкой с использованием первичного ключа fi sh.

CREATE TABLE fish (
  id SERIAL PRIMARY KEY,
  name TEXT
);

CREATE TABLE fishmonths(
  fishid INTEGER,
  start TEXT
  end TEXT
);
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...