Foreign key constrait fail - mysql

I have 3 tables:
create table comuni(
comune varchar(20) primary key,
cap char(5) not null,
abitanti int not null
)ENGINE=InnoDB;
create table mercati(
ubicazione varchar(20) not null,
comune varchar(20) not null,
primary key(ubicazione,comune),
foreign key(comune) references comuni(comune)
)ENGINE=InnoDB;
create table posteggi(
identificativo char(3) not null,
mq int not null,
CHECK(mq>=3),
acquistato bool not null DEFAULT 1,
ubicazione varchar(20) not null,
comune varchar(20) not null,
codice_fiscale char(16),
primary key(identificativo,ubicazione,comune),
foreign key(ubicazione,comune) references mercati(ubicazione,comune),
foreign key(codice_fiscale) references commercianti(codice_fiscale)
)ENGINE=InnoDB;
In the first table I've insert two rows
+-----------+-------+----------+
| comune | cap | abitanti |
+-----------+-------+----------+
| tribano | 35020 | 6000 |
| monselice | 35023 | 5020 |
+-----------+-------+----------+
then in the second one row,
+----------------+--------+------------+----------+----------+
| ubicazione | giorno | ora_inizio | ora_fine | comune |
+----------------+--------+------------+----------+----------+
| piazza mazzini | GI | 07:00:00 | 13:00:00 | tribano |
+----------------+--------+------------+----------+----------+
but when i try to execute
insert into posteggi(identificativo,mq,ubicazione,comune)
values('10',10,'piazza mazzini','tribano');
which exist in table mercati I have this error:
ERROR 1452 (23000): Cannot add or update a child row: a foreign key constraint fails (ntresold-ES.posteggi, CONSTRAINT posteggi_ibfk_1 FOREIGN KEY (ubicazione, comune) REFERENCES mercati (ubicazione, comune))
Yes, the problem was the space before "tribano", I remove it and works with the code in Pheonix's answer

SQL Fiddle
MySQL 5.5.30 Schema Setup:
create table comuni(
comune varchar(20) primary key,
cap char(5) not null,
abitanti int not null
);
create table mercati(
ubicazione varchar(20) not null,
comune varchar(20) not null,
primary key(ubicazione,comune),
foreign key(comune) references comuni(comune)
);
create table posteggi(
identificativo char(3) not null,
mq int not null,
CHECK(mq>=3),
acquistato bool not null DEFAULT 1,
ubicazione varchar(20) not null,
comune varchar(20) not null,
codice_fiscale char(16),
primary key(identificativo,ubicazione,comune),
foreign key(ubicazione,comune) references mercati(ubicazione,comune)
);

Related

Can't create a recursive relationship in MySQL

I need some help, I am trying to create a recursive relation using the code below, but keep getting an error
CREATE TABLE `Employee` (
`SSN` int,
`address` varchar(50),
`salary` varchar(50),
`sex` varchar(50),
`birthDate` varchar(50),
`dependantId` int,
`supervisorId` int,
PRIMARY KEY (`SSN`),
FOREIGN KEY (`dependantId`) REFERENCES `Dependant`(`dependantId`),
FOREIGN KEY (`supervisorId`) REFERENCES `Employee`(`supervisorId`)
);
This is the error I'm getting:
#1005 - Can't create table company recursive.employee (errno: 150 "Foreign key constraint is incorrectly formed")
The table needs an ID column to be "referenceable" by foreign key constraints. That column musst be UNIQUE and ideally NOT NULL as well. A typical solution would look like:
CREATE TABLE Employee (
`SSN` int,
`address` varchar(50),
`salary` varchar(50),
`sex` varchar(50),
`birthDate` varchar(50),
id int not null unique, -- non nullable unique (acts as a key)
dependantId int, -- nullable reference
supervisorId int, -- nullable reference
PRIMARY KEY (`SSN`),
FOREIGN KEY (dependantId) REFERENCES Employee (id),
FOREIGN KEY (supervisorId) REFERENCES Employee (id)
);
In this case dependantId and supervisorId can be null and become references that point to the same table Employee.
As a side note, typically hierarchies only include references to the supervisor and not to the dependant. In your case the latter is somewhat redundant and won't work well if a supervisor has more than one dependant.
the reference should go to the SSN as it is the primary key
So you would get
CREATE TABLE `Employee` (
`SSN` int,
`address` varchar(50),
`salary` varchar(50),
`sex` varchar(50),
`birthDate` varchar(50),
`dependantId` int,
`supervisorId` int,
PRIMARY KEY (`SSN`),
FOREIGN KEY (`dependantId`) REFERENCES `Employee`(`SSN`),
FOREIGN KEY (`supervisorId`) REFERENCES `Employee`(`SSN`)
);
INSERT INTO Employee VALUES (1,'adreess1','10', 'male', '2000-01-01',NULL,NULL)
INSERT INTO Employee VALUES (2,'adreess1','10', 'male', '2000-01-01',NULL,1)
INSERT INTO Employee VALUES (3,'adreess1','10', 'male', '2000-01-01',2,1)
SELECT * FROM Employee
SSN | address | salary | sex | birthDate | dependantId | supervisorId
--: | :------- | :----- | :--- | :--------- | ----------: | -----------:
1 | adreess1 | 10 | male | 2000-01-01 | null | null
2 | adreess1 | 10 | male | 2000-01-01 | null | 1
3 | adreess1 | 10 | male | 2000-01-01 | 2 | 1
db<>fiddle here

How to speed up MYSQL query with multiple joins?

looking for help to speed up this query:
SELECT tickets.ticketid, datenew, products.name
FROM tickets
INNER JOIN ticketlines ON tickets.id = ticketlines.ticket
INNER JOIN products ON ticketlines.product = products.id
INNER JOIN receipts ON receipts.id = tickets.id
WHERE (category !='feb765ef-c8a8-4fa2-969c-90f67fe6b3be' AND category!='888f4893-f300-43b5-9933-d549ade744e0' AND category !='8f2031e8-64a4-4abf-8175-3d2bedd9f950' AND category !='ca370ced-1c3b-434c-905e-ec1bc709543b' AND category !='f92ff0ac-fa11-4a5f-a3dd-e0d9ed9c171a' AND category !='445e8605-1cd9-4714-b3fd-7389ac29c206' and category !='05143c54-8a7e-4ce2-97cc-f84f9cf41395' AND category !='8c78afea-b9e2-44cf-b497-c384045b3202' AND category !='95919f7f-ff2e-4aa1-8110-ef63c022c01b' AND category !='f4f88b05-38a1-4956-9182-4c04a0808df7') AND datedone IS NULL
ORDER BY ticketid
This is from a cash register database that I am using to pull data for order display. The structure is the receipt has the primary id, the timein and timedone(DATEDONE) timestamps. The ticket table has ticket id which is the same as receipt id. Ticketlines table is the line items on the receipt/ticket. And then Products table has the human readable definitions of the products.
The query is to pull all items that aren't completed, i.e. DATEDONE is null, and display the items that were ordered.
Ticket and Receipt tables have 15K rows, Ticketlines has ~20K rows, Products has 1.5k.
Pretty small data. But this query takes over 20 seconds. I think since I am using primary key IDs for everything, I don't need to index anything, but I am a total noob, so I'm happy to be told I'm wrong. I'll appreciate any help and can provide any further details. Thanks!
EDIT:
per comments, I am showing table structures. I'm sorry for the formatting nightmare, I'm unfamiliar with this platform and unsure how to make it more readable :-(
| receipts | CREATE TABLE `receipts` (
`ID` varchar(255) NOT NULL,
`MONEY` varchar(255) NOT NULL,
`DATENEW` datetime NOT NULL,
`ATTRIBUTES` mediumblob,
`PERSON` varchar(255) DEFAULT NULL,
`DATEDONE` datetime DEFAULT NULL,
PRIMARY KEY (`ID`),
KEY `RECEIPTS_FK_MONEY` (`MONEY`),
KEY `RECEIPTS_INX_1` (`DATENEW`),
CONSTRAINT `RECEIPTS_FK_MONEY` FOREIGN KEY (`MONEY`) REFERENCES `closedcash` (`MONEY`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 |
| tickets | CREATE TABLE `tickets` (
`ID` varchar(255) NOT NULL,
`TICKETTYPE` int(11) NOT NULL DEFAULT '0',
`TICKETID` int(11) NOT NULL,
`PERSON` varchar(255) NOT NULL,
`CUSTOMER` varchar(255) DEFAULT NULL,
`STATUS` int(11) NOT NULL DEFAULT '0',
`DONE` varchar(255) DEFAULT NULL,
PRIMARY KEY (`ID`),
KEY `TICKETS_FK_2` (`PERSON`),
KEY `TICKETS_CUSTOMERS_FK` (`CUSTOMER`),
KEY `TICKETS_TICKETID` (`TICKETTYPE`,`TICKETID`),
CONSTRAINT `TICKETS_CUSTOMERS_FK` FOREIGN KEY (`CUSTOMER`) REFERENCES `customers` (`ID`),
CONSTRAINT `TICKETS_FK_2` FOREIGN KEY (`PERSON`) REFERENCES `people` (`ID`),
CONSTRAINT `TICKETS_FK_ID` FOREIGN KEY (`ID`) REFERENCES `receipts` (`ID`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 |
| ticketlines | CREATE TABLE `ticketlines` (
`TICKET` varchar(255) NOT NULL,
`LINE` int(11) NOT NULL,
`PRODUCT` varchar(255) DEFAULT NULL,
`ATTRIBUTESETINSTANCE_ID` varchar(255) DEFAULT NULL,
`UNITS` double NOT NULL,
`PRICE` double NOT NULL,
`TAXID` varchar(255) NOT NULL,
`ATTRIBUTES` mediumblob,
PRIMARY KEY (`TICKET`,`LINE`),
KEY `TICKETLINES_FK_2` (`PRODUCT`),
KEY `TICKETLINES_ATTSETINST` (`ATTRIBUTESETINSTANCE_ID`),
KEY `TICKETLINES_FK_3` (`TAXID`),
CONSTRAINT `TICKETLINES_ATTSETINST` FOREIGN KEY (`ATTRIBUTESETINSTANCE_ID`) REFERENCES `attributesetinstance` (`ID`),
CONSTRAINT `TICKETLINES_FK_2` FOREIGN KEY (`PRODUCT`) REFERENCES `products` (`ID`),
CONSTRAINT `TICKETLINES_FK_3` FOREIGN KEY (`TAXID`) REFERENCES `taxes` (`ID`),
CONSTRAINT `TICKETLINES_FK_TICKET` FOREIGN KEY (`TICKET`) REFERENCES `tickets` (`ID`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 |
| products | CREATE TABLE `products` (
`ID` varchar(255) NOT NULL,
`REFERENCE` varchar(255) NOT NULL,
`CODE` varchar(255) NOT NULL,
`CODETYPE` varchar(255) DEFAULT NULL,
`NAME` varchar(255) NOT NULL,
`PRICEBUY` double NOT NULL,
`PRICESELL` double NOT NULL,
`CATEGORY` varchar(255) NOT NULL,
`TAXCAT` varchar(255) NOT NULL,
`ATTRIBUTESET_ID` varchar(255) DEFAULT NULL,
`STOCKCOST` double DEFAULT NULL,
`STOCKVOLUME` double DEFAULT NULL,
`IMAGE` mediumblob,
`ISCOM` bit(1) NOT NULL DEFAULT b'0',
`ISSCALE` bit(1) NOT NULL DEFAULT b'0',
`ISKITCHEN` bit(1) NOT NULL DEFAULT b'0',
`PRINTKB` bit(1) NOT NULL DEFAULT b'0',
`SENDSTATUS` bit(1) NOT NULL DEFAULT b'0',
`ISSERVICE` bit(1) NOT NULL DEFAULT b'0',
`ATTRIBUTES` mediumblob,
`DISPLAY` varchar(255) DEFAULT NULL,
PRIMARY KEY (`ID`),
UNIQUE KEY `PRODUCTS_INX_0` (`REFERENCE`),
UNIQUE KEY `PRODUCTS_INX_1` (`CODE`),
UNIQUE KEY `PRODUCTS_NAME_INX` (`NAME`),
KEY `PRODUCTS_FK_1` (`CATEGORY`),
KEY `PRODUCTS_TAXCAT_FK` (`TAXCAT`),
KEY `PRODUCTS_ATTRSET_FK` (`ATTRIBUTESET_ID`),
CONSTRAINT `PRODUCTS_ATTRSET_FK` FOREIGN KEY (`ATTRIBUTESET_ID`) REFERENCES `attributeset` (`ID`),
CONSTRAINT `PRODUCTS_FK_1` FOREIGN KEY (`CATEGORY`) REFERENCES `categories` (`ID`),
CONSTRAINT `PRODUCTS_TAXCAT_FK` FOREIGN KEY (`TAXCAT`) REFERENCES `taxcategories` (`ID`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 |
Also, here is EXPLAIN output:
| id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra |
+----+-------------+-------------+------------+--------+--------------------------+---------+---------+------------------------------------+-------+----------+----------------------------------------------+
| 1 | SIMPLE | receipts | NULL | ALL | PRIMARY | NULL | NULL | NULL | 14624 | 10.00 | Using where; Using temporary; Using filesort |
| 1 | SIMPLE | tickets | NULL | eq_ref | PRIMARY | PRIMARY | 767 | receipts.ID | 1 | 100.00 | NULL |
| 1 | SIMPLE | ticketlines | NULL | ref | PRIMARY,TICKETLINES_FK_2 | PRIMARY | 767 | receipts.ID | 1 | 100.00 | Using where |
| 1 | SIMPLE | products | NULL | eq_ref | PRIMARY,PRODUCTS_FK_1 | PRIMARY | 767 | ticketlines.PRODUCT | 1 | 97.97 | Using where |
+----+-------------+-------------+------------+--------+--------------------------+---------+---------+------------------------------------+-------+----------+----------------------------------------------+
4 rows in set, 1 warning (0.04 sec)
Try changing data types of all columns to the minimal required ones.
Add indexes on columns in WHERE.
Add index on ticketlines.ticket.
I ended up deleted 10K rows from every linked table and it queries running in .2 seconds now. I guess absent any more advice, i will be doing annual cleanup of old tickets.

Why won't my SQL table creation work in Codio?

I am trying to complete my homework but am getting an error message saying that the table I'm creating doesn't match what is expected to be input. Here is what the table is supposed to contain:
+-----------+-----------------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+-----------+-----------------+------+-----+---------+----------------+
| id | int(3) unsigned | NO | PRI | NULL | auto_increment |
| room_num | int(4) unsigned | NO | UNI | NULL | |
| course_id | int(3) unsigned | YES | MUL | NULL | |
+-----------+-----------------+------+-----+---------+----------------+
The code I am entering to try and achieve this is:
CREATE TABLE college.classrooms (
id INT(3) UNSIGNED NOT NULL AUTO_INCREMENT,
room_num INT(4) UNSIGNED NOT NULL UNIQUE KEY,
course_id INT(3) UNSIGNED DEFAULT NULL,
PRIMARY KEY (id),
FOREIGN KEY (course_id) REFERENCES college.courses(id)
) AUTO_INCREMENT = 1;
My school uses Codio and it auto checks the table to see if it's correct and that is the error message I'm getting:
[Error]: Create a 'classrooms' table with the requested structure. Reset the database and try again
What am I missing from my code to make this work? I've already created the table it is referencing (courses).
Is it probably failing on the FOREIGN KEY REFERENCES context? You are trying to create a table that is EXPECTING the course_id to be found in a secondary table "college.courses". If the college.courses table is not created yet, this table could never reference it.
Make sure the COURSES table is created FIRST
CREATE TABLE classrooms
(
id INT(3) unsigned primary key NOT NULL AUTO_INCREMENT,
room_num INT(4) unsigned NOT NULL UNIQUE,
course_id INT(3) unsigned DEFAULT NULL,
FOREIGN KEY (course_id) REFERENCES college.courses(id)
)
AUTO_INCREMENT = 1;

Deleting correct in a many-to-many relationship

I've got a short question with a many-to-many relationship.
Here are my tables:
+---------+----------------+
| film_id | title |
+---------+----------------+
| 1 | Apocalypse Now |
+---------+----------------+
+-------------+----------------------+
| category_id | name |
+-------------+----------------------+
| 1 | cool category |
+-------------+----------------------+
| 2 | not so cool category |
+-------------+----------------------+
+---------+-------------+
| film_id | category_id |
+---------+-------------+
| 1 | 1 |
+---------+-------------+
| 1 | 2 |
+---------+-------------+
As you can see there are FKs from the film- and category-table in the film_category-table.
What I want: If one wants to delete a category, then ALL entries in the film_category where the category_id occurs should be deleted, too. BUT not the related films! In addition to that: This should work while deleting a film vice versa! (That's exactly my problem here)
My Question: Can I solve the issue with a FK-definition only or do I have to delete all entries in the film_category-table manually before deleting a film or category?
Your tables should look something like the following. A delete in the film table should delete the rows where the film category has the same id, and vice versa with the film table.
CREATE TABLE `film` (
`film_id` int(10) unsigned NOT NULL AUTO_INCREMENT,
`title` varchar(255) NOT NULL DEFAULT '',
PRIMARY KEY (`film_id`)
) ENGINE=InnoDB;
CREATE TABLE `category` (
`category_id` int(10) unsigned NOT NULL AUTO_INCREMENT,
`name` varchar(255) NOT NULL DEFAULT '',
PRIMARY KEY (`category_id`)
) ENGINE=InnoDB;
CREATE TABLE `film_category` (
`film_category_id` int(10) unsigned NOT NULL AUTO_INCREMENT,
`film_id` int(10) unsigned NOT NULL DEFAULT '0',
`category_id` int(10) unsigned NOT NULL DEFAULT '0',
PRIMARY KEY (`film_category_id`),
KEY `film_id` (`film_id`),
KEY `category_id` (`category_id`),
CONSTRAINT `film_category_ibfk_2` FOREIGN KEY (`category_id`) REFERENCES `category` (`category_id`) ON DELETE CASCADE,
CONSTRAINT `film_category_ibfk_1` FOREIGN KEY (`film_id`) REFERENCES `film` (`film_id`) ON DELETE CASCADE
) ENGINE=InnoDB;
You should also be able to use the following for film_category:
CREATE TABLE `film_category` (
`film_id` int(10) unsigned NOT NULL DEFAULT '0',
`category_id` int(10) unsigned NOT NULL DEFAULT '0',
PRIMARY KEY (`film_id`,`category_id`),
CONSTRAINT `film_category_ibfk_1` FOREIGN KEY (`film_id`) REFERENCES `film` (`film_id`) ON DELETE CASCADE,
CONSTRAINT `film_category_ibfk_2` FOREIGN KEY (`category_id`) REFERENCES `category` (`category_id`) ON DELETE CASCADE
) ENGINE=InnoDB;

effective query on a table with over 1 million record

I am really struggling with the following two queries. I have two tables both with over a million records. The first query runs with 30 seconds and the second one runs with over 7 mins.
Basically I would like to get the count class.id and scan_layers.id based on the Lot. What would be the most effective way to do it?
select count(class.id), count(scan_layers.id), Lot, Verified from class left join scan_layers on (class.ScanLayer = scan_layers.id) group by Lot;
select count(class.id), count(distinct scan_layers.id), Lot, Verified from class left join scan_layers on (class.ScanLayer = scan_layers.id) group by Lot;
As I explain it, they both giving me the same explain.
+----+-------------+--------------------+--------+---------------+------------------------+---------+----------------------------------+---------+----------------------------------------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+--------------------+--------+---------------+------------------------+---------+----------------------------------+---------+----------------------------------------------+
| 1 | SIMPLE | class | index | NULL | defects_scan_layers_fk | 4 | NULL | 4417159 | Using index; Using temporary; Using filesort |
| 1 | SIMPLE | scan_layers | eq_ref | PRIMARY | PRIMARY | 4 | cdb.class.ScanLayer | 1 | |
+----+-------------+--------------------+--------+---------------+------------------------+---------+----------------------------------+---------+----------------------------------------------+
CREATE TABLE `class` (
`id` int(10) unsigned NOT NULL AUTO_INCREMENT,
`ScanLayer` int(10) unsigned NOT NULL,
`Type` enum('Regular','Critical') NOT NULL DEFAULT 'Regular',
PRIMARY KEY (`id`),
UNIQUE KEY `Defect_UNIQUE` (`ScanLayer`),
KEY `class_scan_layers_fk` (`ScanLayer`),
CONSTRAINT `class_scan_layers_fk` FOREIGN KEY (`ScanLayer`) REFERENCES `scan_layers` (`id`) ON UPDATE CASCADE
) ENGINE=InnoDB
CREATE TABLE `scan_layers` (
`id` int(10) unsigned NOT NULL AUTO_INCREMENT,
`LayerInfo` int(10) unsigned NOT NULL,
`Lot` varchar(45) NOT NULL DEFAULT 'DEFAULT',
`PhysicalID` int(10) unsigned NOT NULL,
`Scanned` datetime DEFAULT NULL,
`ScannedMachine` int(10) unsigned DEFAULT NULL,
`DefectsCount` int(10) unsigned NOT NULL DEFAULT '0',
`MovesCount` int(10) unsigned NOT NULL DEFAULT '0',
`Verified` datetime DEFAULT NULL,
`VerifiedMachine` int(10) unsigned DEFAULT NULL,
PRIMARY KEY (`id`),
UNIQUE KEY `ScanLayer_UNIQUE` (`LayerInfo`,`Lot`,`PhysicalID`),
KEY `scan_layers_layer_infos_fk` (`LayerInfo`),
KEY `scan_layers_scanned_machines_fk` (`ScannedMachine`),
KEY `scan_layers_verified_machines_fk` (`VerifiedMachine`),
KEY `scan_layers_verified` (`Verified`),
KEY `scan_layers_lot` (`Lot`),
CONSTRAINT `scan_layers_layer_infos_fk` FOREIGN KEY (`LayerInfo`) REFERENCES `layer_infos` (`id`) ON UPDATE CASCADE,
CONSTRAINT `scan_layers_scanned_machines_fk` FOREIGN KEY (`ScannedMachine`) REFERENCES `machines` (`id`) ON UPDATE CASCADE,
CONSTRAINT `scan_layers_verified_machines_fk` FOREIGN KEY (`VerifiedMachine`) REFERENCES `machines` (`id`) ON UPDATE CASCADE,
) ENGINE=InnoDB
Thanks a lot!