Getting data that is difficult connected with the input data, SQL Query - mysql

Firstly, want to ask you (so my question would be more clear for you) if there an online database diagram tool (?) in which I can input my sql code and it will draw diagramm (with tables and their relationships) for me.
I found this question and tried some tools, but most of them can only create tables and relationships between them, but not allow to import my sql.
(2)
I need to get all classes connected with Teacher.
There are two types of connection: teacher may be the form-master or teacher may taugh this class.
How to get all classes which are connected to teacher.
(3) 1 more additional question: Am I right with constraints?
SQL Scheme (scheme on sqlfiddle.com):
CREATE TABLE `Subject` (
`id` INT(11) NOT NULL AUTO_INCREMENT,
`name` VARCHAR(50) NOT NULL DEFAULT '0',
PRIMARY KEY (`id`)
);
CREATE TABLE `Teacher` (
`id` INT(11) NOT NULL AUTO_INCREMENT,
`firstname` VARCHAR(50) NOT NULL,
`midname` VARCHAR(50) NOT NULL,
`lastname` VARCHAR(50) NOT NULL,
`address` VARCHAR(100) NOT NULL,
`birthdate` DATE NOT NULL,
PRIMARY KEY (`id`)
);
CREATE TABLE `Class` (
`id` INT(11) NOT NULL AUTO_INCREMENT,
`digit` INT(11) NOT NULL,
`char` VARCHAR(50) NOT NULL,
`teacher_id` INT(11) NOT NULL,
PRIMARY KEY (`id`),
INDEX `FK_Class_Teacher` (`teacher_id`),
CONSTRAINT `FK_Class_Teacher` FOREIGN KEY (`teacher_id`) REFERENCES `teacher` (`id`)
);
CREATE TABLE `ClassVsSubject` (
`id` INT(11) NOT NULL AUTO_INCREMENT,
`subject_id` INT(11) NOT NULL,
`class_id` INT(11) NOT NULL,
PRIMARY KEY (`id`),
UNIQUE INDEX `subject_id_class_id` (`subject_id`, `class_id`),
INDEX `FK_ClassVsSubject_Class` (`class_id`),
CONSTRAINT `FK_ClassVsSubject_Class` FOREIGN KEY (`class_id`) REFERENCES `class` (`id`),
CONSTRAINT `FK_ClassVsSubject_Subject` FOREIGN KEY (`subject_id`) REFERENCES `subject` (`id`)
);
CREATE TABLE `TeacherVsSubject` (
`id` INT(11) NOT NULL AUTO_INCREMENT,
`teacher_id` INT(11) NOT NULL,
`subject_id` INT(11) NOT NULL,
PRIMARY KEY (`id`),
INDEX `FK_TeacherVsSubject_Teacher` (`teacher_id`),
INDEX `FK_TeacherVsSubject_Subject` (`subject_id`),
CONSTRAINT `FK_TeacherVsSubject_Teacher` FOREIGN KEY (`teacher_id`) REFERENCES `teacher` (`id`),
CONSTRAINT `FK_TeacherVsSubject_Subject` FOREIGN KEY (`subject_id`) REFERENCES `subject` (`id`)
);

For your second question, use something like:
select *
from Class
where teacher_id = 1
union
select Class.*
from Class
join ClassVsSubject on Class.id = ClassVsSubject.class_id
join TeacherVsSubject on ClassVsSubject.subject_id = TeacherVsSubject.subject_id
where TeacherVsSubject.teacher_id = 1
As you did not state which teacher is the starting point, I used that with id 1.
Please note that union gets rid of duplicate entries, there is no need to treat this separately.
For your data model (question 3), I think one gotcha is that you need different entries in the subject table for different classes and the same subject like 'Maths' or 'English', otherwise, the joins will not work:
Let's say subject "English" has id 1. Now, if the class with id 1 and the class with id 2 both have this subject, you would have the following data in ClassVsSubject:
class_id subject_id
1 1
2 1
How do you want to enter into table TeacherVsSubject that the teacher with id 5 teaches English in class 1, but not in class 2? You cannot! If you enter a record with subject_id 1 and teacher_id 5, this would apply to all classes.
To remedy that, you could make one table from the two ClassVsSubject and TeacherVsSubject. This would be like this:
CREATE TABLE `ClassVsSubjectVsTeacher` (
`id` INT(11) NOT NULL AUTO_INCREMENT,
`subject_id` INT(11) NOT NULL,
`class_id` INT(11) NOT NULL,
`teacher_id` INT(11) NOT NULL,
PRIMARY KEY (`id`),
UNIQUE INDEX `subject_id_class_id` (`subject_id`, `class_id`, `teacher_id`),
INDEX `FK_ClassVsSubjectVsTeacher_Class` (`class_id`),
INDEX `FK_ClassVsSubjectVsTeacher_Teacher` (`teacher_id`),
INDEX `FK_ClassVsSubjectVsTeacher_Subject` (`subject_id`),
CONSTRAINT `FK_ClassVsSubjectVsTeacher_Class` FOREIGN KEY (`class_id`) REFERENCES `class` (`id`),
CONSTRAINT `FK_ClassVsSubjectVsTeacher_Teacher` FOREIGN KEY (`teacher_id`) REFERENCES `teacher` (`id`),
CONSTRAINT `FK_ClassVsSubjectVsTeacher_Subject` FOREIGN KEY (`subject_id`) REFERENCES `subject` (`id`)
);
For the data model, you would not need the id column here, the primary key could be a combined key across all three foreign keys. But - depending on client software - it may be useful to have it. E. g. some OR mapping tools require a single column primary key.

Try this: select * from Class where teacher_id = some_id_from_Teacher_table

Related

How to fix 'MySQL Error: 1822. Missing index for contraint' On creating a composite foreign key

I'm trying to create a table with a composite foreign key, but keep getting met with the error Error Code: 1822. Failed to add the foreign key constraint. Missing index for constraint 'fk_contractdateshistoric_contractdates_multiple' in the referenced table 'contractdates'
I'm using MySQL v8.0.16
I've checked if the column types are different, and I'm not sure what else could be the problem.
Here are the tables that make up the problem, All tables are made happily but the last one that contains the composite key causes the problem.
CREATE TABLE `contracts` (
`ID` int(11) NOT NULL AUTO_INCREMENT,
`Name` varchar(100) DEFAULT NULL,
`CreationDate` datetime DEFAULT NULL,
`CreatedBy` varchar(30) DEFAULT NULL,
`CompletionDate` date DEFAULT NULL,
`Comments` varchar(100) DEFAULT NULL,
PRIMARY KEY (`ID`)
);
CREATE TABLE `fieldheading` (
`ID` int(11) NOT NULL AUTO_INCREMENT,
`fieldTypeID` int(11) DEFAULT NULL,
`fieldCode` int(11) DEFAULT NULL,
`fieldHeading` varchar(100) DEFAULT NULL,
PRIMARY KEY (`ID`)
);
CREATE TABLE `contractdates` (
`ID` int(11) NOT NULL AUTO_INCREMENT,
`DateValue` datetime DEFAULT NULL,
`ContractID` int(11) NOT NULL,
`FieldHeadingID` int(11) NOT NULL,
PRIMARY KEY (`ID`),
UNIQUE KEY `uq_contractdates_contractID_FieldHeading_ID` (`ContractID`,`FieldHeadingID`),
KEY `fk_contractdates_contracts_id_idx` (`ContractID`),
KEY `fk_contractdates_fieldheading_id_idx` (`FieldHeadingID`),
CONSTRAINT `fk_contractdates_fieldheading_id` FOREIGN KEY (`FieldHeadingID`) REFERENCES `fieldheading` (`id`),
CONSTRAINT `fk_contractdates_contracts_id` FOREIGN KEY (`ContractID`) REFERENCES `contracts` (`id`)
) COMMENT='Table to hold the dates for a contract, one row is one date for a specific contract';
CREATE TABLE `contractdateshistoric` (
`ID` int(11) NOT NULL AUTO_INCREMENT,
`ContractID` int(11) NOT NULL,
`ContractDateCurrentID` int(11) NOT NULL,
`FieldHeadingID` int(11) NOT NULL,
`ChangedByID` int(11) NOT NULL,
`DateValue` datetime NOT NULL,
`TimeStampChanged` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
PRIMARY KEY (`ID`),
KEY `fk_contractdateshistoric_contractdates_mutiple_idx` (`ContractID`, `FieldHeadingID`, `ContractDateCurrentID`),
CONSTRAINT `fk_contractdateshistoric_contractdates_multiple` FOREIGN KEY (`ContractID`, `FieldHeadingID`, `ContractDateCurrentID`) REFERENCES `contractdates` (`contractid`, `fieldheadingid`, `id`)
) COMMENT='Audit trail of the dates';
Since you are using Composite FK in the table contractdates try adding composite index as well
KEY `fk_contractdates_mutiple_idx` (`ContractID`,`FieldHeadingID`,`ID`)
Whole create statement
CREATE TABLE `contractdates` (
`ID` int(11) NOT NULL AUTO_INCREMENT,
`DateValue` datetime DEFAULT NULL,
`ContractID` int(11) NOT NULL,
`FieldHeadingID` int(11) NOT NULL,
PRIMARY KEY (`ID`),
KEY `fk_contractdates_contracts_id_idx` (`ContractID`),
KEY `fk_contractdates_fieldheading_id_idx` (`FieldHeadingID`),
KEY `fk_contractdates_mutiple_idx` (`ContractID`,`FieldHeadingID`,`ID`),
CONSTRAINT `fk_contractdates_fieldheading_id` FOREIGN KEY (`FieldHeadingID`) REFERENCES `fieldheading` (`id`),
CONSTRAINT `fk_contractdates_contracts_id` FOREIGN KEY (`ContractID`) REFERENCES `contracts` (`id`)
) COMMENT='Table to hold the dates for a contract, one row is one date for a specific contract';
It's trying to tell you "you haven't created a necessary unique index on contractdates, that covers the columns (contractid, fieldheadingid, id) so I cannot create a foreign key on contractdateshistoric that refers to this set of columns when determining the single parent row"
I'm not sure why you're creating an fk that references 3 columns when contractdates has a pk that is just the ID column.
If a contractdateshistoric records refers to a single contractdates record as its parent, the historic record should have a contractdateid column that refers to contractdates.id - no need for multiple columns. Copy the pattern you used to relate a contractdates to its parent contract, and you'll be fine
I have tried by creating the keys individually for the columns, Please find the updated query:
CREATE TABLE `contractdateshistoric` (
`ID` INT(11) NOT NULL AUTO_INCREMENT,
`ContractID` INT(11) NOT NULL,
`ContractDateCurrentID` INT(11) NOT NULL,
`FieldHeadingID` INT(11) NOT NULL,
`ChangedByID` INT(11) NOT NULL,
`DateValue` DATETIME NOT NULL,
`TimeStampChanged` TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
PRIMARY KEY (`ID`),
KEY `fk_contractdateshistoric_contractdates_mutiple_idx` (`ContractID`),
KEY `fk_contractdateshistoric_contractdates_mutiple_idx1` (`FieldHeadingID`),
KEY `fk_contractdateshistoric_contractdates_mutiple_idx2` (`ContractDateCurrentID`),
CONSTRAINT `fk_contractdateshistoric_contractdates_multiple` FOREIGN KEY (`ContractID`)
REFERENCES `contractdates` (`contractid`),
CONSTRAINT `fk_contractdateshistoric_contractdates_multiple1` FOREIGN KEY (`FieldHeadingID`)
REFERENCES `contractdates` (`fieldheadingid`),
CONSTRAINT `fk_contractdateshistoric_contractdates_multiple2` FOREIGN KEY (`ContractDateCurrentID`)
REFERENCES `contractdates` (`id`)
);
It works fine.

MySQL Temporary Table with Group By and Group Concat Extremely Slow

I'm trying to build out a fairly simple temporary table. The table will end up being 2 columns:
1 A product ID
2 A string of concatenated compliance data in a format that can be consumed later
CREATE TEMPORARY TABLE products.compliances_data
(INDEX product_id_idx (product_id))
SELECT
products.product_id,
GROUP_CONCAT(JSON_OBJECT('compliance_code', cc.compliance_code, 'compliance_full_name', pc.full_name, 'compliance_web_description_short', pc.web_description_short) SEPARATOR ' - ') as compliances
FROM products.products products
LEFT OUTER JOIN products.material_compliance_map cc on products.material_id = cc.material_id
LEFT OUTER JOIN products.compliances pc on cc.compliance_id = pc.compliance_id
GROUP BY products.part_number
The table gathers and joins information from 3 tables.
The products table is the main source of information. The products table has a column for material_id.
The material_compiance_map table. This is a many-to-many table that maps material_id's to compliance_id's
The compliances table. This is the table where the actual data is stored that I need to pull from to build out the concatenated object.
The problem is the creation of the temporary table takes 3-4 minutes to run yet only yields about 1.2 million entries which seems incredibly slow.
Running an explain on the select portion of the query yields:
Explain on select image
There are only 642 entries in the material_comliance_map so there's not an awful lot of data here that needs to be traversed.
I've tried removing the group_concat and that seems to speed up the query about 33%. The problem seems to revolve around the group by statement.
How can I improve the speed when building this temp table?
EDIT:
Schemas:
material_compliance_map schema
'material_compliance_map'
CREATE TABLE `material_compliance_map` (
`material_id` int(11) NOT NULL,
`material_code` varchar(20) COLLATE utf8_unicode_ci NOT NULL,
`compliance_id` int(11) NOT NULL,
`compliance_code` varchar(20) COLLATE utf8_unicode_ci NOT NULL,
PRIMARY KEY (`material_id`,`compliance_id`),
KEY `fk_compliance_id_material_compliances_compliances` (`compliance_id`),
KEY `fk_material_id_material_compliances_materials` (`material_id`),
CONSTRAINT `fk_compliance_id_material_compliances_compliances` FOREIGN KEY (`compliance_id`) REFERENCES `compliances` (`compliance_id`) ON UPDATE CASCADE,
CONSTRAINT `fk_material_id_material_compliances_materials` FOREIGN KEY (`material_id`) REFERENCES `materials` (`material_id`) ON UPDATE CASCADE
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci
compliances schema:
'compliances'
CREATE TABLE `compliances` (
`compliance_id` int(11) NOT NULL AUTO_INCREMENT,
`compliance_code` varchar(20) NOT NULL,
`full_name` varchar(155) DEFAULT NULL,
`web_description_short` varchar(45) DEFAULT NULL,
PRIMARY KEY (`compliance_id`),
UNIQUE KEY `compliance_id_UNIQUE` (`compliance_id`),
UNIQUE KEY `compliance_code_UNIQUE` (`compliance_code`)
) ENGINE=InnoDB AUTO_INCREMENT=15 DEFAULT CHARSET=latin1
products schema:
'products'
CREATE TABLE `products` (
`part_number` varchar(27) NOT NULL,
`material_code` varchar(30) DEFAULT NULL,
`material_id` int(11) DEFAULT NULL,
`size_code` varchar(15) DEFAULT NULL,
`size_id` int(11) DEFAULT NULL,
`erp_description_1` varchar(31) DEFAULT NULL,
`erp_description_2` varchar(31) DEFAULT NULL,
`search_description` varchar(250) DEFAULT NULL,
`weight_lbs` decimal(8,4) DEFAULT NULL,
`part_number_prefix` varchar(15) DEFAULT NULL,
`tight_tolerance` tinyint(4) DEFAULT NULL,
`product_id` int(11) NOT NULL AUTO_INCREMENT,
PRIMARY KEY (`product_id`),
UNIQUE KEY `part_number_UNIQUE` (`part_number`),
UNIQUE KEY `product_id_UNIQUE` (`product_id`),
KEY `fk_material_id_products_materials` (`material_id`),
KEY `fk_size_id_products_sizes` (`size_id`),
KEY `product_id` (`product_id`),
KEY `size_id_idx` (`size_id`),
KEY `size_id_productsidx` (`size_id`),
KEY `material_id_idx` (`material_id`),
CONSTRAINT `fk_material_id_products_materials` FOREIGN KEY (`material_id`) REFERENCES `materials` (`material_id`),
CONSTRAINT `fk_size_id_products_sizes` FOREIGN KEY (`size_id`) REFERENCES `sizes` (`size_id`)
) ENGINE=InnoDB AUTO_INCREMENT=1140987 DEFAULT CHARSET=latin1

Mysql Connot add foreign key constraint. how can I resolve it?

I tried to excute the query. but a error was occurred. the error message is 'Cannot add foreign key constraint'.
I supposed to create this table. but it didn't work.
CREATE TABLE IF NOT EXISTS `mydb`.`member` (
`idseq` INT(1) NOT NULL AUTO_INCREMENT,
`id` VARCHAR(50) NOT NULL,
`pw` VARCHAR(20) NOT NULL,
`name` VARCHAR(50) NOT NULL,
`email` VARCHAR(45) NOT NULL,
`mobile0` VARCHAR(3) NOT NULL,
`mobile1` VARCHAR(3) NOT NULL,
`mobile2` VARCHAR(4) NOT NULL,
`mobile3` VARCHAR(4) NOT NULL,
`birth` DATE NOT NULL,
`admin_YN` VARCHAR(45) NOT NULL DEFAULT 'N',
`reg_date` DATE NOT NULL,
`upd_date` DATE NOT NULL,
PRIMARY KEY (`idseq`, `id`))
ENGINE = InnoDB
AUTO_INCREMENT = 6
DEFAULT CHARACTER SET = utf8;
CREATE TABLE IF NOT EXISTS `mydb`.`reservation` (
`reservation_seq` INT(11) NOT NULL AUTO_INCREMENT,
`user_id` VARCHAR(50) NOT NULL,
`playMv_seq` INT(11) NOT NULL,
`reservaion_seat_code` VARCHAR(20) NOT NULL,
`reservaion_seat_num` INT(11) NOT NULL,
`reservation_charge` VARCHAR(20) NOT NULL,
`reservation_date` DATETIME NOT NULL,
PRIMARY KEY (`reservation_seq`, `user_id`, `playMv_seq`),
FOREIGN KEY (`user_id`)
REFERENCES `mydb`.`member` (`id`)
)
ENGINE = InnoDB
AUTO_INCREMENT = 8
DEFAULT CHARACTER SET = utf8;
So I checked it detail from a query'show engine innodb status. the detail error message is
Error in foreign key constraint of table mydb/reservation:
FOREIGN KEY (`user_id`)
REFERENCES `mydb`.`member` (`id`)
Cannot find an index in the referenced table where the
referenced columns appear as the first columns, or column types
in the table and the referenced table do not match for constraint.
Note that the internal storage type of ENUM and SET changed in
tables created with >= InnoDB-4.1.12, and such columns in old tables
cannot be referenced by such columns in new tables.
how can I resolve the error
You're trying to create a foreign key referencing the id column of the target table:
FOREIGN KEY (`user_id`)
REFERENCES `mydb`.`member` (`id`)
But what is the actual key on that target table?:
PRIMARY KEY (`idseq`, `id`)
It's not id, if the composite of idseq and id. In order to reference that as a foreign key, you need local columns which match that:
`user_idseq` INT(1) NOT NULL,
`user_id` VARCHAR(50) NOT NULL,
And use both of them for the foreign key:
FOREIGN KEY (`user_idseq`, `user_id`)
REFERENCES `mydb`.`member` (`idseq`, `id`)
(Side Note: That primary key in member looks pretty strange to me in the first place. Why can't idseq by itself be the primary key? What is the purpose of id?)

MySQL MariaDB wont create Table with a foreign key

I'm having a problem with my SQL Tables. So I have my Usertable:
CREATE TABLE IF NOT EXISTS `user` (
`ID` int(11) NOT NULL AUTO_INCREMENT,
`NICKNAME` varchar(50) NOT NULL,
`PASSWORD` varchar(255) NOT NULL,
`EMAIL` varchar(50) DEFAULT NULL,
PRIMARY KEY (`NICKNAME`),
UNIQUE KEY `ID` (`ID`)
) ;
This table already exists and was created without any problems. I Want to create a score Table like this:
CREATE TABLE IF NOT EXISTS `scores` (
`ID` int(11) NOT NULL AUTO_INCREMENT,
`NICKNAME` varchar(50) NOT NULL,
`HIGHSCORE` int(11) NOT NULL,
PRIMARY KEY (`ID`),
FOREIGN KEY (NICKNAME) REFERENCES USER(Nickname)
)
On execution of the query I get this errormassage:
**#1005 - Kann Tabelle `xxxxx`.`scores` nicht erzeugen (Fehler: 150 "Foreign key constraint is incorrectly formed") (Details…)**
Its in German and says cant create Table, Error 150, I cant see where the key constraint is wrong, I used the same syntax in postgreSQL and it worked fine, but somehow MySQL is not accepting it. Any Ideas?
That is strange. If nickname is indeed the primary key, then your code should work.
It is much more nature, though, to use the auto-incremented column as the primary key. If you want the nickname, then use a join when you query.
So:
CREATE TABLE IF NOT EXISTS `scores` (
`ID` int(11) NOT NULL AUTO_INCREMENT,
UserId int(11) NOT NULL,
`NICKNAME` varchar(50) NOT NULL,
`HIGHSCORE` int(11) NOT NULL,
PRIMARY KEY (`ID`),
FOREIGN KEY (UserId) REFERENCES USER(Id)
);
user - is a keyword.
It may be a good idea to use another table name e.g. "tblUser",
or use quotes again ``
FOREIGN KEY (NICKNAME) REFERENCES `USER`(ID)
Thanks to Mr. Gordon Linoff I was able to find my Mistake:
I had to declare NICKNAME to be declared UNIQUE, only then the FOREIGN KEY constraint could be added to other tables
CREATE TABLE IF NOT EXISTS `user` (
`ID` int(11) NOT NULL AUTO_INCREMENT,
`NICKNAME` varchar(50) NOT NULL,
`PASSWORD` varchar(255) NOT NULL,
`EMAIL` varchar(100) DEFAULT NULL,
PRIMARY KEY (`NICKNAME`),
UNIQUE KEY `ID` (`ID`),
UNIQUE KEY `NICKNAME` (`NICKNAME`)
);

Only allow one unique foreign key for primary

I have 3 tables in mysql, One is a Company table, the other is a license table and the last is a joining table between both primary keys, When a person adds a company id to the license id in the joining table, it allows multiple companies to exist for one license, this cannot happen, so I need to do something that will only allow one company id for one license id
heres the tables
Table license
CREATE TABLE `License` (
`license_id` int(11) NOT NULL AUTO_INCREMENT,
`license_number` varchar(45) NOT NULL,
`start_date` date NOT NULL,
`end_date` date NOT NULL,
`duration` int(11) NOT NULL,
`expiry_date` date NOT NULL,
`product_id` int(11) DEFAULT NULL,
PRIMARY KEY (`license_id`)
) ENGINE=InnoDB AUTO_INCREMENT=21 DEFAULT CHARSET=latin1;
;
Company Table
CREATE TABLE `Company` (
`company_id` int(11) NOT NULL AUTO_INCREMENT,
`name` varchar(255) NOT NULL,
`physical_address` varchar(255) DEFAULT NULL,
`postal_address` varchar(255) DEFAULT NULL,
`reseller_id` int(11) DEFAULT NULL,
PRIMARY KEY (`company_id`)
) ENGINE=InnoDB AUTO_INCREMENT=18 DEFAULT CHARSET=latin1;
and Joining table
CREATE TABLE `CompanyLicense` (
`license_id` int(11) NOT NULL,
`company_id` int(11) NOT NULL,
PRIMARY KEY (`license_id`,`company_id`),
KEY `companlicence_company_fk_idx` (`company_id`),
CONSTRAINT `companylicense_company_fk` FOREIGN KEY (`company_id`) REFERENCES `Company` (`company_id`) ON DELETE CASCADE ON UPDATE CASCADE,
CONSTRAINT `companylicense_license_fk` FOREIGN KEY (`license_id`) REFERENCES `License` (`license_id`) ON DELETE CASCADE ON UPDATE CASCADE
) ENGINE=InnoDB DEFAULT CHARSET=latin1;
So far i have this
INSERT INTO CompanyLicense (license_id, company_id) VALUES
('2','6') on duplicate key update license_id = '2';
doesnt seem to do the job
You need to make company unique in companylicense:
ALTER TABLE companylicense ADD UNIQUE KEY (company)
or better yet, make company a field in license instead of having a link table.