Мое приложение MySQL позволяет пользователям создавать bookmarks и систематизировать их с помощью tags.

tag добавляется в bookmark со средней таблицей БД MySQL bookmark_tag_relationship

Я хотел бы добавить Foreign Key для автоматического удаления всех записей в bookmark_tag_relationship при удалении записи Bookmarks.

Все удаленные записи bookmark_tag_relationship будут иметь столбец bookmark_id, который соответствует столбцу id в удаленной записи закладки.

Как я могу правильно настроить это на основе трех структур таблиц, показанных ниже?

Неудачная попытка №1

Я пробовал примерно так:

ALTER TABLE bookmarks ADD FOREIGN KEY (`id`)
    REFERENCES bookmark_tag_relationship(`bookmark_id`);

Он возвратил ошибку без информации только о том, что не мог ее создать.


закладки таблицы

--
-- Table structure for table `bookmarks`
--

CREATE TABLE IF NOT EXISTS `bookmarks` (
  `id` int(20) NOT NULL,
  `url_id` int(20) DEFAULT NULL,
  `user_id` int(30) DEFAULT NULL,
  `name` varchar(255) DEFAULT NULL,
  `url` varchar(255) DEFAULT NULL,
  `favicon_url` varchar(255) DEFAULT NULL,
  `project_url` varchar(255) DEFAULT NULL,
  `github_url` varchar(255) DEFAULT NULL,
  `demo_url` int(255) DEFAULT NULL,
  `local_demo_url` varchar(255) DEFAULT NULL,
  `image1` varchar(255) DEFAULT NULL,
  `image2` varchar(255) DEFAULT NULL,
  `image3` varchar(255) DEFAULT NULL,
  `image4` varchar(255) DEFAULT NULL,
  `description` text,
  `notes` text,
  `tags_string` varchar(255) DEFAULT NULL,
  `click_count` int(10) NOT NULL DEFAULT '0',
  `tag_count` int(10) NOT NULL DEFAULT '0',
  `created_on` datetime DEFAULT NULL,
  `updated_on` datetime DEFAULT NULL,
  `last_viewed_on` datetime DEFAULT NULL,
  `active` int(1) NOT NULL DEFAULT '1'
) ENGINE=InnoDB AUTO_INCREMENT=3 DEFAULT CHARSET=latin1;

теги таблиц

--
-- Table structure for table `tags`
--

CREATE TABLE IF NOT EXISTS `tags` (
  `id` int(11) NOT NULL,
  `user_id` int(11) DEFAULT NULL,
  `name` varchar(100) DEFAULT NULL,
  `description` text,
  `color` varchar(10) DEFAULT NULL,
  `bookmark_count` int(11) NOT NULL DEFAULT '0',
  `active` int(11) NOT NULL DEFAULT '1'
) ENGINE=InnoDB AUTO_INCREMENT=5 DEFAULT CHARSET=latin1;

таблица bookmark_tag_relationship

--
-- Table structure for table `bookmark_tag_relationship`
--

CREATE TABLE IF NOT EXISTS `bookmark_tag_relationship` (
  `id` int(11) NOT NULL,
  `bookmark_id` int(30) NOT NULL,
  `tag_id` int(30) NOT NULL
) ENGINE=InnoDB DEFAULT CHARSET=latin1;
0
JasonDavis 19 Фев 2016 в 21:24

5 ответов

Лучший ответ

Три вопроса:

  • Вы не определили первичный ключ в закладках таблицы (или любом другом); В комментариях вы пояснили, что они у вас действительно есть, так что это не проблема;
  • У вас есть ограничение внешнего ключа, определенное в противоположном направлении. Вы должны определить его в дочерней таблице;
  • Вам необходимо добавить предложение ON DELETE CASCADE.

Итак, выполните это, и он будет работать (вы можете пропустить первый, поскольку в комментариях вы пояснили, что у вас уже есть первичный ключ):

ALTER TABLE bookmarks ADD
    CONSTRAINT PRIMARY KEY(id);

ALTER TABLE bookmark_tag_relationship
    ADD FOREIGN KEY (bookmark_id)
    REFERENCES bookmarks(id)
    ON DELETE CASCADE;

Теперь вы можете удалить закладку, например:

DELETE FROM bookmarks WHERE id = 1;

... и связанные записи в bookmark_tag_relationship будут удалены в той же транзакции.

Некоторые дополнительные замечания:

  • Разница между int(20) и int(30), которая у вас есть для типов первичного и внешнего ключей, не может быть очень полезной. Это не влияет на ограничение, но я все же предлагаю согласовать это следующим образом:
    ALTER TABLE bookmark_tag_relationship 
        MODIFY bookmark_id int(20) NOT NULL;
  • Необязательно заключать имена таблиц и столбцов обратными кавычками. Они необходимы только тогда, когда вы выбрали зарезервированные слова для этих имен, но этого вы все равно хотели бы избежать.
1
Community 20 Июн 2020 в 09:12

Есть несколько причин, по которым ваш внешний ключ не работает.

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

ALTER TABLE table_name
ADD PRIMARY KEY (table_column)

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

В вашей таблице bookmark_tag_relationship bookmark_id - INT (30) , но в вашей таблице закладок * ваш столбец 'id' равен ** INT (20) . Вы должны убедиться, что они оба одинаковы. Поэтому либо измените идентификатор с закладок на INT (30), либо измените другой идентификатор на INT (20).

И, наконец, ваш запрос внешнего ключа перевернут. Вы хотите наоборот.

ALTER TABLE bookmark_tag_relationship ADD FOREIGN KEY (`bookmark_id`)      
REFERENCES bookmarks(`id`)
ON DELETE CASCADE;

Вы хотите, чтобы bookmark_tag_relationship удалялся при удалении закладки, а не наоборот.

0
Chin Leung 19 Фев 2016 в 18:55

EDIT: ваш внешний ключ также не работает, потому что у вас нет первичного ключа. Внешний ключ - это ссылка на первичный ключ.

Я бы установил триггер для закладок при удалении.

DELIMITER $$
CREATE DEFINER=`username`@`%` TRIGGER `bookmarks_ADEL` AFTER DELETE ON `bookmarks` FOR EACH ROW
BEGIN
    DELETE FROM bookmark_tag_relationship WHERE bookmark_id = old.id;
END

Когда строка из закладок удаляется, она берет этот идентификатор и удаляет строку из bookmark_tag_relationship.

Вам нужно установить первичные ключи в обеих этих таблицах, скорее всего, ID

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

1
Joe Swindell 19 Фев 2016 в 18:52

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

mysql> show create table bookmarks\G
*************************** 1. row ***************************
       Table: bookmarks
Create Table: CREATE TABLE `bookmarks` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `title` varchar(255) DEFAULT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=4 DEFAULT CHARSET=latin1
1 row in set (0.00 sec)

mysql> show create table tags\G
*************************** 1. row ***************************
       Table: tags
Create Table: CREATE TABLE `tags` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `name` varchar(255) DEFAULT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=6 DEFAULT CHARSET=latin1
1 row in set (0.00 sec)

mysql> show create table bookmarks_tags\G
*************************** 1. row ***************************
       Table: bookmarks_tags
Create Table: CREATE TABLE `bookmarks_tags` (
  `bookmark_id` int(11) NOT NULL DEFAULT '0',
  `tag_id` int(11) NOT NULL DEFAULT '0',
  PRIMARY KEY (`bookmark_id`,`tag_id`),
  CONSTRAINT `bookmarks_tags_ibfk_1` FOREIGN KEY (`bookmark_id`) REFERENCES `bookmarks` (`id`) ON DELETE CASCADE
) ENGINE=InnoDB DEFAULT CHARSET=latin1
1 row in set (0.01 sec)

mysql> select * from bookmarks;
+----+-----------+
| id | title     |
+----+-----------+
|  1 | bookmark1 |
|  2 | bookmark2 |
|  3 | bookmark3 |
+----+-----------+
3 rows in set (0.00 sec)

mysql> select * from tags;
+----+------+
| id | name |
+----+------+
|  1 | tag1 |
|  2 | tag2 |
|  3 | tag3 |
|  4 | tag4 |
|  5 | tag5 |
+----+------+
5 rows in set (0.00 sec)

mysql> select * from bookmarks_tags;
+-------------+--------+
| bookmark_id | tag_id |
+-------------+--------+
|           1 |      1 |
|           1 |      2 |
|           1 |      3 |
|           2 |      1 |
|           2 |      4 |
|           3 |      5 |
+-------------+--------+
6 rows in set (0.00 sec)

mysql> delete from bookmarks where title = 'bookmark1';
Query OK, 1 row affected (0.01 sec)

mysql> select * from bookmarks; select * from tags; select * from bookmarks_tags;
+----+-----------+
| id | title     |
+----+-----------+
|  2 | bookmark2 |
|  3 | bookmark3 |
+----+-----------+
2 rows in set (0.00 sec)

+----+------+
| id | name |
+----+------+
|  1 | tag1 |
|  2 | tag2 |
|  3 | tag3 |
|  4 | tag4 |
|  5 | tag5 |
+----+------+
5 rows in set (0.01 sec)

+-------------+--------+
| bookmark_id | tag_id |
+-------------+--------+
|           2 |      1 |
|           2 |      4 |
|           3 |      5 |
+-------------+--------+
3 rows in set (0.00 sec)
0
gimbel0893 19 Фев 2016 в 18:56

Попробуйте добавить КАСКАД УДАЛЕНИЯ на внешний ключ.

ALTER TABLE bookmark_tag_relationship ADD FOREIGN KEY (`bookmark_id`) 
REFERENCES bookmarks(`id`) 
ON DELETE CASCADE;
0
Caio Baracat 19 Фев 2016 в 18:50