Как проверить, существует ли пара в таблице SQL.скованность - PullRequest
0 голосов
/ 11 октября 2018

У меня есть пара PILOT1 и PILOT2 SIN с SHIP ID.Я не хочу этого:

ship1   111 222 4   20  idk 23.33   gop

ship1   222 111 4   20  idk 23.33   gop

Посмотрите, как shipID то же самое, и те же пилоты управляют кораблем.Я хочу способ ограничить это.Это действительно, так как идентификаторы пилота разные:

ship1   111 222 4   20  idk 23.33   gop

ship1   232 111 4   20  idk 23.33   gop

CREATE TABLE Ship (
    shipID varchar(30) NOT NULL,
    pilot1_SIN varchar(11) NOT NULL,
    pilot2_SIN varchar(11) NOT NULL,
    years_in_operation INT,
    num_of_seats INT,
    manufacturer varchar(30),
    advertising_revenue FLOAT,
    fuel_type varchar(15)
    PRIMARY KEY (shipID, pilot1_SIN, pilot2_SIN),
    FOREIGN KEY (pilot1_SIN) REFERENCES Pilot(SINumber),
    FOREIGN KEY (pilot2_SIN) REFERENCES Pilot(SINumber),
    CONSTRAINT check_pilots CHECK (pilot1_SIN != pilot2_SIN)
);

Ответы [ 3 ]

0 голосов
/ 11 октября 2018

К сожалению, как отмечает @Barmar, даже в версии 8.0 MySQL просто игнорирует любые CHECK CONSTRAINTS

Вы можете использовать триггер BEFORE INSERT, как предложено @ TheImpaler

Для нестандартного решения вы можете использовать сгенерированный столбец

pilot_check_unique VARCHAR(23) AS (CONCAT(
  LEAST(pilot1_SIN,pilot2_SIN), ':', GREATEST(pilot1,pilot2) 
)) NOT NULL UNIQUE

Если таблица не InnoDB, вам придется создать столбец STORED, поместив STOREDдо UNIQUE это, конечно, увеличит дисковое пространство, используемое таблицей

К сожалению, это не подтвердит, что pilot1 не равно pilot2, я думаю, вы могли бы добавить

pilot_check_not_equal TINYINT(1) AS (
  CASE WHEN pilot1_SIN != pilot2_SIN THEN 1 END CASE
) NOT NULL

но я не уверен на 100%, что это будет разрешено

NB Сказав все это, я обнаружил, что в моих проектах всегда есть проблемы проверки, которые не могут быть легко решенына уровне базы данных.Я хотел бы проверить это дело на прикладном уровне.Пока у вас есть только одна область кода, которая INSERT s или UPDATE s этого кода, у вас все будет в порядке.

ADDENDUM

Другой вариантразделить ваш стол Ship на Ship и Ship_pilot

CREATE TABLE Ship (
    shipID varchar(30) NOT NULL,
    years_in_operation INT,
    num_of_seats INT,
    manufacturer varchar(30),
    advertising_revenue FLOAT,
    fuel_type varchar(15)
    PRIMARY KEY (shipID)
);

CREATE TABLE Ship_Pilot (
    shipID varchar(30) NOT NULL,
    pilot_SIN varchar(11) NOT NULL,
    position TINYINT(3) UNSIGNED NOT NULL
    PRIMARY KEY (shipID, pilot_SIN),
    FOREIGN KEY (pilot_SIN) REFERENCES Pilot(SINumber),
    UNIQUE KEY (shipID, position)
);

Это не позволит вам дублировать пилотов или позиции для корабля, но позволит вам 0-256 разных пилотов на корабль

ASIDE

Я бы также предложил следующие

  • Использование UNSIGNED целочисленных типов для идентификаторов
  • Использование UNSIGNED целые числа для num_of_seats и years_in_operation, предположительно, они не могут быть отрицательными
  • Использовать отдельные таблицы для каждого из fuel_type и manufacturer и ссылаться на них с целым числом UNSIGNED, а не дублировать имена
  • В вашем корабельном столе есть составной ПК, это позволит использовать одно и то же shipID несколько раз в одной и той же таблице (с разными пилотами) - это правильно?
  • Использовать DECIMAL илицелочисленный тип для advertising_revenue для точности
0 голосов
/ 11 октября 2018

Вот еще одна идея ...

DROP TABLE IF EXISTS my_table;

CREATE TABLE my_table (id1 INT NOT NULL,id2 INT NOT NULL,PRIMARY KEY(id1,id2));

INSERT INTO my_table SELECT LEAST(4,9),GREATEST(4,9);

SELECT * FROM my_table;
+-----+-----+
| id1 | id2 |
+-----+-----+
|   4 |   9 |
+-----+-----+

INSERT INTO my_table SELECT LEAST(4,9),GREATEST(4,9);
ERROR 1062 (23000): Duplicate entry '4-9' for key 'PRIMARY'
0 голосов
/ 11 октября 2018

Вы можете сделать:

CREATE TABLE Ship (
shipID varchar(30) NOT NULL,
pilot1_SIN varchar(11) NOT NULL,
pilot2_SIN varchar(11) NOT NULL,
years_in_operation INT,
num_of_seats INT,
manufacturer varchar(30),
advertising_revenue FLOAT,
fuel_type varchar(15)
PRIMARY KEY (shipID, pilot1_SIN, pilot2_SIN),
FOREIGN KEY (pilot1_SIN) REFERENCES Pilot(SINumber),
FOREIGN KEY (pilot2_SIN) REFERENCES Pilot(SINumber),
);

create unique index IX_Unique on (Ship (least(pilot1_SIN, pilot2_SIN), greatest(pilot1_SIN, pilot2_SIN)));
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...