web-dev-qa-db-fra.com

il est possible de référencer une colonne comme plusieurs clés étrangères

J'ai peu de tables et je veux référencer une colonne du tableau PDF à plusieurs autres tables .enter image description here

par exemple, si PDF tableau select sortie ressemble à ceci:

ITEM_TYPE  ITEM_ID  QUANTITY

1          23       3
2          12       1

il me dit:

Les PDF ont 3 produits de roue de voiture et 1 en-tête de modèle de voiture ci-dessus;

J'ai écrit du code SQL, mais ne fonctionne pas correctement:

CREATE TABLE `pdf_created` (
    `id` INT(10) UNSIGNED NOT NULL UNIQUE AUTO_INCREMENT,
    `pdf_id` INT(10) NOT NULL,
    `item_type` INT(3) UNSIGNED NOT NULL,
    `item_id` INT(10) UNSIGNED NOT NULL,
    `quantity` INT(3) NOT NULL,
    PRIMARY KEY (`id`),
    KEY `FK_pdf_id` (`pdf_id`),
    CONSTRAINT `FK_pdf_id` FOREIGN KEY (`pdf_id`) REFERENCES `pdf` (`id`),
    KEY `FK_item_type` (`item_type`),
    CONSTRAINT `FK_item_type` FOREIGN KEY (`item_type`) REFERENCES `item` (`id`) ON DELETE CASCADE ON UPDATE CASCADE,
    KEY `FK_item_id` (`item_id`),
    CONSTRAINT `FK_item_id` FOREIGN KEY (`item_id`) REFERENCES `product` (`id`) ON DELETE CASCADE ON UPDATE CASCADE,
    CONSTRAINT `FK_item_id` FOREIGN KEY (`item_id`) REFERENCES `service` (`id`) ON DELETE CASCADE ON UPDATE CASCADE,
    CONSTRAINT `FK_item_id` FOREIGN KEY (`item_id`) REFERENCES `header` (`id`) ON DELETE CASCADE ON UPDATE CASCADE
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

CREATE TABLE `header` (
    `id` INT(10) UNSIGNED NOT NULL UNIQUE AUTO_INCREMENT,
    `title` VARCHAR(255),
    `desc` VARCHAR(65535),
    PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

CREATE TABLE `service` (
    `id` INT(10) UNSIGNED NOT NULL UNIQUE AUTO_INCREMENT,
    `desc` VARCHAR(65535) NOT NULL,
    `price` DECIMAL(5,2) NOT NULL,
    `active` INT(1) NOT NULL,
    PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

CREATE TABLE `product` (
    `id` INT(10) UNSIGNED NOT NULL UNIQUE AUTO_INCREMENT,
    `category_id` INT(3) UNSIGNED NOT NULL,
    `symbol` VARCHAR(255),
    `desc` VARCHAR(65535), 
    `price` DECIMAL(5,2) NOT NULL,
    PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

il est possible de le créer?

20
insict

Non.

Autrement dit, vous ne pouvez pas créer une contrainte de clé étrangère de cette façon. Vous pouvez cependant utiliser une clé étrangère sans contrainte de clé étrangère.

Toute clé étrangère est, est la valeur de la clé primaire d'une autre table (ou d'un autre enregistrement de la même table), qui peut être utilisée dans des jointures. En fait, vous pouvez référencer des champs autres que la clé primaire, s'il vous suffit d'utiliser la valeur pour les jointures.

Cependant, une contrainte de clé étrangère indique à la base de données d'appliquer la règle selon laquelle pour chaque valeur de clé étrangère d'une table, la table référencée a un enregistrement avec comme clé primaire. Faire en sorte que chaque clé étrangère de la table PDF ait une clé primaire IN ALL FOUR TABLES ne fonctionnera pas pour vous. Allez-y, utilisez le champ pour référencer d'autres enregistrements, mais ne créez simplement aucune contrainte de clé étrangère.

22
Marlin Pierce

Le problème que vous avez rencontré s'appelle Polymorphic Associations

Veuillez vous référer à cette question: MySQL - Contraintes conditionnelles de clé étrangère

4
Browny Lin

Cela devrait être possible. Un problème potentiel est que vos trois contraintes de clé étrangère ont le même nom. 

2
Dan Bracuk

Non, un champ de clé étrangère est destiné à référencer une table.

Si vous aviez les contraintes FK décrites, un champ item_id ferait référence à la même valeur de clé primaire dans les trois tables. Il est très probable que la clé primaire souhaitée dans les trois tables différentes ait des clés primaires différentes.

Ce que vous voulez, c'est qu'un enregistrement (ligne) fasse référence à des enregistrements dans les tables Produit, En-tête et Service. Pour ce faire, vous devez utiliser trois champs différents, un pour chaque clé étrangère.

Je remarque également que la table Item a les trois clés étrangères nécessaire. Vous pouvez avoir la table PDF avec un champ qui référence Item, et l'enregistrement dans Item fait référence aux trois autres tables.

1
Marlin Pierce

le nom de la contrainte de clé étrangère doit être différent de celui-ci La clé primaire et la colonne de table de clé étrangère doivent avoir le même type de données comme celui-ci.

CREATE TABLE `neo_address_t` (
  `address_id` varchar(8) NOT NULL,
  `address_line_1` varchar(45) NOT NULL,
  `address_line_2` varchar(45) NOT NULL,
  `address_line_3` varchar(45) NOT NULL,
  `address_city` varchar(45) NOT NULL,
  `address_zipcode` varchar(45) NOT NULL,
  `address_state` varchar(45) NOT NULL DEFAULT 'Karnataka',
  `address_country` varchar(45) NOT NULL DEFAULT 'INDIA',
  `created_by` varchar(8) DEFAULT NULL,
  `created_on` timestamp NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
  `last_modified_by` varchar(8) DEFAULT NULL,
  `last_modified_date` timestamp NULL DEFAULT '0000-00-00 00:00:00',
  `Refer_ID` int(11) DEFAULT NULL,
  `a_id` varchar(255) DEFAULT NULL,
  `referenceid` varchar(255) DEFAULT NULL,
  PRIMARY KEY (`address_id`),
  KEY `hospital_ID_FK_idx` (`Refer_ID`),
  CONSTRAINT `Patient_ID_FK` FOREIGN KEY (`Refer_ID`) REFERENCES `neo_patient_t` (`patient_ID`) ON DELETE NO ACTION ON UPDATE NO ACTION,
  CONSTRAINT `hospital_ID_FK` FOREIGN KEY (`Refer_ID`) REFERENCES `neo_hospital_t` (`hospital_id`) ON DELETE NO ACTION ON UPDATE CASCADE,
  CONSTRAINT `staff_ID_FK` FOREIGN KEY (`Refer_ID`) REFERENCES `neo_staff_t` (`staff_ID`) ON DELETE NO ACTION ON UPDATE NO ACTION
)     
ENGINE=InnoDB DEFAULT CHARSET=utf8$$
0
Rahul Pandey

Théoriquement, vous ne pouvez pas appliquer plusieurs clés étrangères à une seule colonne . Vous pouvez également appliquer cette procédure à l'aide de procédures dans lesquelles vous validez l'entrée qui existe dans plusieurs tables et effectuez l'opération nécessaire . Le tableau doit être effectué selon les procédures qui valident la condition requise, sinon cela entraînerait une violation de l'intégrité.

0
acsinha

Oui c'est possible. Même si cela semble un peu étrange.

J'aimerais tout d'abord montrer une capture d'écran de MySQL Workbench pour attester de son efficacité.

 Table editor

... et pour ceux qui disent "Vous avez peut-être oublié d'appliquer les modifications" ... Voici la capture d'écran du navigateur de schéma:

 Schema browser

et enfin le dump exporté avec quelques exemples de données:

-- MySQL dump 10.13  Distrib 5.7.12, for Win64 (x86_64)
--
-- Host: localhost    Database: multiple_foreign_keys
-- ------------------------------------------------------
-- Server version   5.7.17-log

/*!40101 SET @OLD_CHARACTER_SET_CLIENT=@@CHARACTER_SET_CLIENT */;
/*!40101 SET @OLD_CHARACTER_SET_RESULTS=@@CHARACTER_SET_RESULTS */;
/*!40101 SET @OLD_COLLATION_CONNECTION=@@COLLATION_CONNECTION */;
/*!40101 SET NAMES utf8 */;
/*!40103 SET @OLD_TIME_ZONE=@@TIME_ZONE */;
/*!40103 SET TIME_ZONE='+00:00' */;
/*!40014 SET @OLD_UNIQUE_CHECKS=@@UNIQUE_CHECKS, UNIQUE_CHECKS=0 */;
/*!40014 SET @OLD_FOREIGN_KEY_CHECKS=@@FOREIGN_KEY_CHECKS, FOREIGN_KEY_CHECKS=0 */;
/*!40101 SET @OLD_SQL_MODE=@@SQL_MODE, SQL_MODE='NO_AUTO_VALUE_ON_ZERO' */;
/*!40111 SET @OLD_SQL_NOTES=@@SQL_NOTES, SQL_NOTES=0 */;

--
-- Table structure for table `header`
--

DROP TABLE IF EXISTS `header`;
/*!40101 SET @saved_cs_client     = @@character_set_client */;
/*!40101 SET character_set_client = utf8 */;
CREATE TABLE `header` (
  `id` int(10) unsigned NOT NULL AUTO_INCREMENT,
  `title` varchar(255) DEFAULT NULL,
  `desc` varchar(255) DEFAULT NULL,
  PRIMARY KEY (`id`),
  UNIQUE KEY `id` (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=43 DEFAULT CHARSET=utf8;
/*!40101 SET character_set_client = @saved_cs_client */;

--
-- Dumping data for table `header`
--

LOCK TABLES `header` WRITE;
/*!40000 ALTER TABLE `header` DISABLE KEYS */;
INSERT INTO `header` VALUES (42,'Header','Test Header');
/*!40000 ALTER TABLE `header` ENABLE KEYS */;
UNLOCK TABLES;

--
-- Table structure for table `pdf_created`
--

DROP TABLE IF EXISTS `pdf_created`;
/*!40101 SET @saved_cs_client     = @@character_set_client */;
/*!40101 SET character_set_client = utf8 */;
CREATE TABLE `pdf_created` (
  `id` int(10) unsigned NOT NULL AUTO_INCREMENT,
  `pdf_id` int(10) NOT NULL,
  `item_type` int(3) unsigned NOT NULL,
  `item_id` int(10) unsigned NOT NULL,
  `quantity` int(3) NOT NULL,
  PRIMARY KEY (`id`),
  UNIQUE KEY `id` (`id`),
  KEY `fk_item_to_product_idx` (`item_id`),
  CONSTRAINT `fk_item_to_header` FOREIGN KEY (`item_id`) REFERENCES `header` (`id`) ON DELETE NO ACTION ON UPDATE NO ACTION,
  CONSTRAINT `fk_item_to_product` FOREIGN KEY (`item_id`) REFERENCES `product` (`id`) ON DELETE NO ACTION ON UPDATE NO ACTION,
  CONSTRAINT `fk_item_to_service` FOREIGN KEY (`item_id`) REFERENCES `service` (`id`) ON DELETE NO ACTION ON UPDATE NO ACTION
) ENGINE=InnoDB AUTO_INCREMENT=2 DEFAULT CHARSET=utf8;
/*!40101 SET character_set_client = @saved_cs_client */;

--
-- Dumping data for table `pdf_created`
--

LOCK TABLES `pdf_created` WRITE;
/*!40000 ALTER TABLE `pdf_created` DISABLE KEYS */;
INSERT INTO `pdf_created` VALUES (1,2,5,42,1);
/*!40000 ALTER TABLE `pdf_created` ENABLE KEYS */;
UNLOCK TABLES;

--
-- Table structure for table `product`
--

DROP TABLE IF EXISTS `product`;
/*!40101 SET @saved_cs_client     = @@character_set_client */;
/*!40101 SET character_set_client = utf8 */;
CREATE TABLE `product` (
  `id` int(10) unsigned NOT NULL AUTO_INCREMENT,
  `category_id` int(3) unsigned NOT NULL,
  `symbol` varchar(255) DEFAULT NULL,
  `desc` varchar(255) DEFAULT NULL,
  `price` decimal(5,2) NOT NULL,
  PRIMARY KEY (`id`),
  UNIQUE KEY `id` (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=43 DEFAULT CHARSET=utf8;
/*!40101 SET character_set_client = @saved_cs_client */;

--
-- Dumping data for table `product`
--

LOCK TABLES `product` WRITE;
/*!40000 ALTER TABLE `product` DISABLE KEYS */;
INSERT INTO `product` VALUES (42,13,'product','desc',10.00);
/*!40000 ALTER TABLE `product` ENABLE KEYS */;
UNLOCK TABLES;

--
-- Table structure for table `service`
--

DROP TABLE IF EXISTS `service`;
/*!40101 SET @saved_cs_client     = @@character_set_client */;
/*!40101 SET character_set_client = utf8 */;
CREATE TABLE `service` (
  `id` int(10) unsigned NOT NULL AUTO_INCREMENT,
  `desc` varchar(255) NOT NULL,
  `price` decimal(5,2) NOT NULL,
  `active` int(1) NOT NULL,
  PRIMARY KEY (`id`),
  UNIQUE KEY `id` (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=43 DEFAULT CHARSET=utf8;
/*!40101 SET character_set_client = @saved_cs_client */;

--
-- Dumping data for table `service`
--

LOCK TABLES `service` WRITE;
/*!40000 ALTER TABLE `service` DISABLE KEYS */;
INSERT INTO `service` VALUES (42,'some service',5.00,1);
/*!40000 ALTER TABLE `service` ENABLE KEYS */;
UNLOCK TABLES;
/*!40103 SET TIME_ZONE=@OLD_TIME_ZONE */;

/*!40101 SET SQL_MODE=@OLD_SQL_MODE */;
/*!40014 SET FOREIGN_KEY_CHECKS=@OLD_FOREIGN_KEY_CHECKS */;
/*!40014 SET UNIQUE_CHECKS=@OLD_UNIQUE_CHECKS */;
/*!40101 SET CHARACTER_SET_CLIENT=@OLD_CHARACTER_SET_CLIENT */;
/*!40101 SET CHARACTER_SET_RESULTS=@OLD_CHARACTER_SET_RESULTS */;
/*!40101 SET COLLATION_CONNECTION=@OLD_COLLATION_CONNECTION */;
/*!40111 SET SQL_NOTES=@OLD_SQL_NOTES */;

-- Dump completed on 2018-08-27 10:31:41

Utilisez 'Data Import/Restore' dans MySQL Workbench si vous souhaitez le tester à la place d'un éditeur de script SQL.

MAIS vous ne devriez pas utiliser l'incrémentation automatique pour les tables product, header et service qui sont référencées par pdf_created.item_id, car ce serait une coïncidence si les trois avaient le même identifiant. Vous devez attribuer l'identifiant (l'identifiant de l'élément).

0
René Link