Pregunta

I'm trying to make an database and one of my tables use composite primary keys. This works fine until I try to make a foreign key to a separate table using the 2nd composite key. Error given is "ERROR 1005 (HY000): Can't create table '.kesharaproducts\production.frm' (errno: 150)"

Here's the code.

create table stocks(
rawMatBatchID VARCHAR(4) NOT NULL,
finishedGoodsBatchID VARCHAR(4) NOT NULL,
rawMaterialID VARCHAR(4) NOT NULL,
finishedMaterialID VARCHAR(4) NOT NULL,
supplierID VARCHAR(5) NOT NULL,
rawMaterialType VARCHAR(10) NOT NULL,
finishedMaterialType VARCHAR(10) NOT NULL,
rawMatWeight VARCHAR(5) NOT NULL,
finishedGoodsWeightKg INT(5) NOT NULL,
finishedGoodsWeightG INT(5) NOT NULL,
finishedGoodsUnits INT(5) NOT NULL,
finishedGoodsDate VARCHAR(15) NOT NULL,
rawMatDate VARCHAR(15) NOT NULL,
PRIMARY KEY (finishedGoodsBatchID, rawMatBatchID),
CONSTRAINT FOREIGN KEY (finishedMaterialID) REFERENCES finishedMaterials(finishedMaterialID),
CONSTRAINT FOREIGN KEY (supplierID) REFERENCES supplierDetails(supplierID),
CONSTRAINT FOREIGN KEY (rawMaterialID) REFERENCES rawMaterials(rawMaterialID))ENGINE=INNODB;

The table above use the composite primary key.

create table transport(
transportID VARCHAR(4) NOT NULL,
vehicleID VARCHAR(4) NOT NULL,
finishedGoodsBatchID VARCHAR(4) NOT NULL,
finishedGoodsUnits INT(5) NOT NULL,
finishedGoodsWeightKg INT(5),
finishedGoodsWeightG INT(5),
transportDate VARCHAR(15),
CONSTRAINT PRIMARY KEY (transportID),
CONSTRAINT FOREIGN KEY (vehicleID) REFERENCES vehicles(vehicleID),
CONSTRAINT FOREIGN KEY (finishedGoodsBatchID) REFERENCES stocks(finishedGoodsBatchID)
)ENGINE=INNODB;

Table above used the first of the composite keys and works fine.

create table production(
productionBatchID VARCHAR(4) NOT NULL,
finishedMaterialID VARCHAR(4) NOT NULL,
rawMaterialID VARCHAR(4) NOT NULL,
productionDate VARCHAR(15),
rawMatBatchID VARCHAR(4),
initialWeight INT(5),
beforeWeight INT(5),
afterWeight INT(5),
finalWeight INT(5),
packingWeight INT(5),
noOfUnits INT(5),
wastage INT(5),
CONSTRAINT PRIMARY KEY (productionBatchID),
CONSTRAINT FOREIGN KEY (finishedMaterialID) REFERENCES finishedMaterials(finishedMaterialID),
CONSTRAINT FOREIGN KEY (rawMaterialID) REFERENCES rawMaterials(rawMaterialID),
CONSTRAINT FOREIGN KEY (rawMatBatchID) REFERENCES stocks(rawMatBatchID))ENGINE=INNODB;

But in the table above, which uses the 2nd composite primary as a foreign key, it gives out the error. How to fix this? These are the last three tables. All the other referred tables are created. I didn't post all the tables here, too long. When I remove "CONSTRAINT FOREIGN KEY (rawMatBatchID) REFERENCES stocks(rawMatBatchID)" from the last table and add the table it gets added. But not with the referral to the 2nd composite key...

¿Fue útil?

Solución

Table stocks does not have 2 primary keys. It has one and only one. It is a composite key, made from 2 parts: (finishedGoodsBatchID, rawMatBatchID).

If you want to have FOREIGN KEY constraints that reference a table, you should reference a primary key (or a unique key) of that table. The whole of it. So, in this case the whole composite primary key of stocks and not a part of it.

That makes the foreign key from transport wrong, too. MySQL allows it but you will have problems if you leave it like this. A foreign key should be able to somehow identify rows in the parent table but (finishedGoodsBatchID) cannot (identify rows) alone.

So, the transport definition should be:

CREATE TABLE transport(
    transportID VARCHAR(4) NOT NULL,
    vehicleID VARCHAR(4) NOT NULL,
    finishedGoodsBatchID VARCHAR(4) NOT NULL,
    rawMatBatchID VARCHAR(4) NOT NULL,                            -- added
    finishedGoodsUnits INT(5) NOT NULL,
    finishedGoodsWeightKg INT(5),
    finishedGoodsWeightG INT(5),
    transportDate VARCHAR(15),
    CONSTRAINT 
      PRIMARY KEY (transportID),
    CONSTRAINT 
      FOREIGN KEY (vehicleID) 
      REFERENCES vehicles(vehicleID),
    CONSTRAINT                                                    -- changed
      FOREIGN KEY (finishedGoodsBatchID, rawMatBatchID) 
      REFERENCES stocks (finishedGoodsBatchID, rawMatBatchID)
) ENGINE=INNODB;

A similar change should be done in the definitioon of the production table, too.

Otros consejos

The foreign key should have the same pair of columns as the primary key it references.

The reason yourtransport table worked is that InnoDB supports a funny non-standard extension to SQL so that a foreign key can reference one column in a composite key, but only if it references a left subset of the columns.

Your production table references only the second column in the referenced primary key, and it can't work that way.

I'm not sure what you're trying to do with this design. Despite InnoDB's ability to do the reference against a subset of columns, this is non-standard SQL, and not recommended.

It would be better to add both columns in the stocks primary key to both tables that reference it, and make a composite foreign key to reference a composite primary key.

You are referencing tables that are just not there yet. Disable foreign keys, create your tables, and then re-enable your foreign keys.

SET foreign_key_checks = 0;

create tables...

SET foreign_key_checks = 1;
Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top