Creating an Associative entity in mysql - mysql

I am trying to combine the two tables through the Associative entity LINEITEM and it keeps giving me errors when i try to set the primary and foreign keys in the code. Any help would be appreciated. Thanks!
Database changed
mysql> select * from STUDENT;
+---------+--------+-----+
| SFName | SLName | SID |
+---------+--------+-----+
| Geno | Smith | 1 |
| Kevin | White | 2 |
| Tavon | Austin | 3 |
| Charles | Sims | 4 |
| Mario | Alford | 5 |
+---------+--------+-----+
5 rows in set (0.00 sec)
mysql> select * from ASSIGNMENT;
+------------------+-------+
| AName | AType |
+------------------+-------+
| Final Exam | T |
| Formal Report | H |
| Grammar Exercise | H |
| Informal Report | H |
| Midterm | T |
| Resume | H |
+------------------+-------+
6 rows in set (0.00 sec)
create table LINEITEM
( SID int
, AName varchar
, LIGrade decimal(5,2)
, primary key(SID, AName)
, foreign key (SID) references STUDENT(SID)
, foreign key (AName) references ASSIGNMENT(AName)
);
ERROR 1064 (42000): You have an error in your SQL syntax;
check the manual that corresponds to your MySQL server version for the right syntax to use near
' LIGrade decimal(5,2), primary key(SID, AName), foreign key (SID) references STU' at line 1
mysql>

Related

How can we verify an internal index is created for a relation?

From https://stackoverflow.com/a/51181742/3284469
If the table has no PRIMARY KEY or suitable UNIQUE index, InnoDB
internally generates a hidden clustered index named GEN_CLUST_INDEX on
a synthetic column containing row ID values. The rows are ordered by
the ID that InnoDB assigns to the rows in such a table. The row ID is
a 6-byte field that increases monotonically as new rows are inserted.
Thus, the rows ordered by the row ID are physically in insertion
order.
My mysql version is:
$ mysql --version
mysql Ver 8.0.11 for Linux on x86_64 (MySQL Community Server - GPL)
I followed the commands there to verify the internal index is created, but the last command doesn't show any index has been created. Why is that? Thanks.
Note that I changed the last command a little bit, because the original command gives me Unknown table 'INNODB_INDEX_STATS' in information_schema error.
# Create the table
create table test.check_table (id int, description varchar(10)) ENGINE = INNODB;
# Verify that there is no primary or unique column
desc test.check_table;
+-------------+-------------+------+-----+---------+-------+
| Field | Type | Null | Key | Default | Extra |
+-------------+-------------+------+-----+---------+-------+
| id | int(11) | YES | | NULL | |
| description | varchar(10) | YES | | NULL | |
+-------------+-------------+------+-----+---------+-------+
# Insert some values
insert into test.check_table values(1, 'value-1');
insert into test.check_table values(2, 'value-2');
insert into test.check_table values(null, 'value-3');
insert into test.check_table values(4, null);
insert into test.check_table values(1, 'value-1');
# Verify table
select * from test.check_table;
+------+-------------+
| id | description |
+------+-------------+
| 1 | value-1 |
| 2 | value-2 |
| NULL | value-3 |
| 4 | NULL |
| 1 | value-1 |
+------+-------------+
# Verify that the GEN_CLUST_INDEX index is auto-created.
select * from INFORMATION_SCHEMA.INNODB_INDEX_STATS where TABLE_SCHEMA='test' and TABLE_NAME = 'check_table';
ERROR 1109 (42S02): Unknown table 'INNODB_INDEX_STATS' in information_schema
SELECT DISTINCT TABLE_NAME, COLUMN_NAME , INDEX_NAME FROM INFORMATION_SCHEMA.STATISTICS WHERE TABLE_SCHEMA = 'test' AND TABLE_NAME='check_table';
Empty set (0.00 sec)
In all versions of MySQL that I've been able to find, the INNODB_INDEX_STATS table is located in the mysql database, not INFORMATION_SCHEMA. This appears to be an error in the post you're referencing.
mysql> select * from mysql.innodb_index_stats where table_name = 'check_table';
+---------------+-------------+-----------------+---------------------+--------------+------------+-------------+-----------------------------------+
| database_name | table_name | index_name | last_update | stat_name | stat_value | sample_size | stat_description |
+---------------+-------------+-----------------+---------------------+--------------+------------+-------------+-----------------------------------+
| test | check_table | GEN_CLUST_INDEX | 2018-07-10 11:34:01 | n_diff_pfx01 | 5 | 1 | DB_ROW_ID |
| test | check_table | GEN_CLUST_INDEX | 2018-07-10 11:34:01 | n_leaf_pages | 1 | NULL | Number of leaf pages in the index |
| test | check_table | GEN_CLUST_INDEX | 2018-07-10 11:34:01 | size | 1 | NULL | Number of pages in the index |
+---------------+-------------+-----------------+---------------------+--------------+------------+-------------+-----------------------------------+
This index isn't a "real" index from the perspective of SQL (it doesn't appear in the output of DESCRIBE, and can't be modified or dropped), so it isn't shown in INFORMATION_SCHEMA.STATISTICS.
For version 8.0.11, the table innodb_index_stats is located in mysql schema in lieu of INFORMATION_SCHEMA. Following the commands, the last query gives result as below:
mysql> select VERSION();
+-----------+
| VERSION() |
+-----------+
| 8.0.11 |
+-----------+
mysql> select * from mysql.innodb_index_stats where database_name='test' and table_name = 'check_table';
+---------------+-------------+-----------------+---------------------+--------------+------------+-------------+-----------------------------------+
| database_name | table_name | index_name | last_update | stat_name | stat_value | sample_size | stat_description |
+---------------+-------------+-----------------+---------------------+--------------+------------+-------------+-----------------------------------+
| test | check_table | GEN_CLUST_INDEX | 2018-07-10 18:57:45 | n_diff_pfx01 | 5 | 1 | DB_ROW_ID |
| test | check_table | GEN_CLUST_INDEX | 2018-07-10 18:57:45 | n_leaf_pages | 1 | NULL | Number of leaf pages in the index |
| test | check_table | GEN_CLUST_INDEX | 2018-07-10 18:57:45 | size | 1 | NULL | Number of pages in the index |
+---------------+-------------+-----------------+---------------------+--------------+------------+-------------+-----------------------------------+
Also, the post referenced in the question creates a second table with a primary key specified. The index verification for that query gives:
mysql> create table test.check_table_2 (id int, description varchar(10), PRIMARY KEY(id)) ENGINE = INNODB;
mysql> desc check_table_2;
+-------------+-------------+------+-----+---------+-------+
| Field | Type | Null | Key | Default | Extra |
+-------------+-------------+------+-----+---------+-------+
| id | int(11) | NO | PRI | NULL | |
| description | varchar(10) | YES | | NULL | |
+-------------+-------------+------+-----+---------+-------+
mysql> select * from mysql.innodb_index_stats where database_name='test' and table_name = 'check_table_2';
+---------------+---------------+------------+---------------------+--------------+------------+-------------+-----------------------------------+
| database_name | table_name | index_name | last_update | stat_name | stat_value | sample_size | stat_description |
+---------------+---------------+------------+---------------------+--------------+------------+-------------+-----------------------------------+
| test | check_table_2 | PRIMARY | 2018-07-10 19:00:39 | n_diff_pfx01 | 0 | 1 | id |
| test | check_table_2 | PRIMARY | 2018-07-10 19:00:39 | n_leaf_pages | 1 | NULL | Number of leaf pages in the index |
| test | check_table_2 | PRIMARY | 2018-07-10 19:00:39 | size | 1 | NULL | Number of pages in the index |
+---------------+---------------+------------+---------------------+--------------+------------+-------------+-----------------------------------+

why this result use column of parent table in subquery

create table teacher (
id int,
name varchar(126),
primary key(id)
)DEFAULT CHARSET=utf8 ENGINE=InnoDB;
create table class (
id int,
name varchar(126),
t_id int,
primary key(id),
foreign key (t_id) references teacher(id) on delete cascade on update cascade
)DEFAULT CHARSET=utf8 ENGINE=InnoDB;
data in tables
mysql> select * from teacher ;
+----+------+
| id | name |
+----+------+
| 1 | yang |
| 2 | yan |
+----+------+
2 rows in set (0.00 sec)
mysql> select * from class ;
+----+---------+------+
| id | name | t_id |
+----+---------+------+
| 1 | math | 1 |
| 2 | english | 2 |
+----+---------+------+
2 rows in set (0.00 sec)
sql I execute
mysql> select * from class where t_id = (select t_id from teacher where name = 'yang');
+----+---------+------+
| id | name | t_id |
+----+---------+------+
| 1 | math | 1 |
| 2 | english | 2 |
+----+---------+------+
how this sql executed and t_id parsed in subsql;
ps:this sql is not what I want, a bug one, but want to know how this run in mysql.

Select rows that are indirectly referenced in another table

PREPARATION
Consider this script to create a MySQL dummy-database:
CREATE SCHEMA `zzz_dummy` ;
CREATE TABLE `zzz_dummy`.`subtable2` (
`id` INT NOT NULL UNIQUE,
`col1` VARCHAR(45) NULL,
PRIMARY KEY (`id`));
CREATE TABLE `zzz_dummy`.`subtable1` (
`id` INT NOT NULL UNIQUE,
`ref_subtab2` INT NULL,
PRIMARY KEY (`id`));
CREATE TABLE `zzz_dummy`.`maintable` (
`id` INT NOT NULL UNIQUE,
`ref_subtab1` INT NULL,
PRIMARY KEY (`id`));
ALTER TABLE `zzz_dummy`.`maintable`
ADD INDEX `fk_subtab1_idx` (`ref_subtab1` ASC);
ALTER TABLE `zzz_dummy`.`maintable`
ADD CONSTRAINT `fk_subtab1`
FOREIGN KEY (`ref_subtab1`)
REFERENCES `zzz_dummy`.`subtable1` (`id`)
ON DELETE NO ACTION
ON UPDATE NO ACTION;
ALTER TABLE `zzz_dummy`.`subtable1`
ADD INDEX `fk_subtab2_idx` (`ref_subtab2` ASC);
ALTER TABLE `zzz_dummy`.`subtable1`
ADD CONSTRAINT `fk_subtab2`
FOREIGN KEY (`ref_subtab2`)
REFERENCES `zzz_dummy`.`subtable2` (`id`)
ON DELETE NO ACTION
ON UPDATE NO ACTION;
INSERT INTO zzz_dummy.subtable2 VALUES
(1,'ref_val_1'),
(2,'ref_val_2'),
(3,'no_ref');
INSERT INTO zzz_dummy.subtable1 VALUES
(1,'1'),
(2,'2'),
(3,'3');
INSERT INTO zzz_dummy.maintable VALUES
(1,'1'),
(2,'2'),
(3,'1'),
(4,'1'),
(5,'2'),
(6,'1');
This will produce the following tables and entries:
maintable:
+----+-------------+
| id | ref_subtab1 |
+----+-------------+
| 1 | 1 |
| 3 | 1 |
| 4 | 1 |
| 6 | 1 |
| 2 | 2 |
| 5 | 2 |
+----+-------------+
subtable1:
+----+-------------+
| id | ref_subtab2 |
+----+-------------+
| 1 | 1 |
| 2 | 2 |
| 3 | 3 |
+----+-------------+
subtable2:
+----+-----------+
| id | col1 |
+----+-----------+
| 1 | ref_val_1 |
| 2 | ref_val_2 |
| 3 | no_ref |
+----+-----------+
PROBLEM
As you can see, the column ref_subtab1 in maintable references id in subtable1, which column ref_subtab2 finally references id in subtable2. I want to select all rows in subtable2 that are indirectly referenced in aforementioned manner.
I have tried
SELECT subtable2.* FROM zzz_dummy.subtable2
INNER JOIN zzz_dummy.maintable
INNER JOIN zzz_dummy.subtable1
WHERE zzz_dummy.maintable.ref_subtab1=zzz_dummy.subtable1.id
AND zzz_dummy.subtable1.ref_subtab2=zzz_dummy.subtable2.id;
but this returns 6 results, one for every match in maintable:
+----+-----------+
| id | col1 |
+----+-----------+
| 1 | ref_val_1 |
| 1 | ref_val_1 |
| 1 | ref_val_1 |
| 1 | ref_val_1 |
| 2 | ref_val_2 |
| 2 | ref_val_2 |
+----+-----------+
I do not want redundant values, I would like it to return:
+----+-----------+
| id | col1 |
+----+-----------+
| 1 | ref_val_1 |
| 2 | ref_val_2 |
+----+-----------+
Can this be done efficiently with a MySQL statement?
As already commented use distinct to get the unique result combination and also move those conditions from WHERE clause to JOIN ON condition like
SELECT distinct subtable2.*
FROM zzz_dummy.subtable2
INNER JOIN zzz_dummy.subtable1
ON zzz_dummy.subtable1.ref_subtab2 = zzz_dummy.subtable2.id
INNER JOIN zzz_dummy.maintable
ON zzz_dummy.maintable.ref_subtab1 = zzz_dummy.subtable1.id;

How to solve mysql ERROR 1062 (23000): Duplicate entry '' for key 'UK_ability_shortname'

I am trying to add a unique key to a column and am getting an self explanatory error of
MariaDB [dnd]> ALTER TABLE ability
-> ADD UNIQUE INDEX UK_ability_shortname (shortname);
ERROR 1062 (23000): Duplicate entry '' for key 'UK_ability_shortname'
But the thing is that I cannot see any duplicates
MariaDB [INFORMATION_SCHEMA]> select * from INNODB_SYS_INDEXES WHERE NAME LIKE 'UK_%';
+----------+---------------------------------+----------+------+----------+---------+-------+
| INDEX_ID | NAME | TABLE_ID | TYPE | N_FIELDS | PAGE_NO | SPACE |
+----------+---------------------------------+----------+------+----------+---------+-------+
| 1733 | UK_food_food | 563 | 2 | 1 | 4 | 558 |
| 1737 | UK_type_type | 565 | 2 | 1 | 4 | 560 |
| 2077 | UK_invite_status_status | 763 | 2 | 1 | 4 | 752 |
| 2586 | UK_tool_class_name | 1093 | 2 | 1 | 4 | 1082 |
| 2591 | UK_food_drink_lodging | 1097 | 2 | 2 | 4 | 1086 |
| 2595 | UK_lifestyle_expenses_lifestyle | 1100 | 2 | 1 | 4 | 1089 |
| 2691 | UK_weapon_name | 1173 | 2 | 1 | 4 | 1162 |
| 2692 | UK_weapon_property_name | 1174 | 2 | 1 | 4 | 1163 |
| 2696 | UK_ability_name | 1183 | 2 | 1 | 4 | 1172 |
+----------+---------------------------------+----------+------+----------+---------+-------+
9 rows in set (0.00 sec)
Any ideas what else I can check to find out why the DB thinks there is a conflict in name or am I exceeding some index name limit?
The table definition that I am trying to alter.
CREATE TABLE `ability` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`name` varchar(50) NOT NULL,
`shortname` char(3) NOT NULL,
`description` text,
PRIMARY KEY (`id`),
UNIQUE KEY `UK_ability_name` (`name`)
) ENGINE=InnoDB AUTO_INCREMENT=3 DEFAULT CHARSET=utf8 COMMENT='Page 175'
Using: Server version: 10.0.15-MariaDB MariaDB Server
Let me know if I can provide any other information.
The error message means there are at least two rows that have the same value for the column shortname ('': the empty string). MariaDB consequently cannot create a unique index on that column. Search for any (other) duplicate values in the column with this query:
SELECT
shortname,
GROUP_CONCAT(id)
FROM
ability
GROUP BY
shortname
HAVING
COUNT(0) > 1

How to prevent Duplicate records from my table Insert ignore does not work here

mysql> select * from emp;
+-----+---------+------+------+------+
| eno | ename | dno | mgr | sal |
+-----+---------+------+------+------+
| 1 | rama | 1 | NULL | 2000 |
| 2 | kri | 1 | 1 | 3000 |
| 4 | kri | 1 | 2 | 3000 |
| 5 | bu | 1 | 2 | 2000 |
| 6 | bu | 1 | 1 | 2500 |
| 7 | raa | 2 | NULL | 2500 |
| 8 | rrr | 2 | 7 | 2500 |
| 9 | sita | 2 | 7 | 1500 |
| 10 | dlksdgj | 2 | 2 | 2000 |
| 11 | dlksdgj | 2 | 2 | 2000 |
| 12 | dlksdgj | 2 | 2 | 2000 |
| 13 | dlksdgj | 2 | 2 | 2000 |
| 14 | dlksdgj | 2 | 2 | 2000 |
+-----+---------+------+------+------+
Here is my table. I want to eliminate or prevent insertion of the duplicate records, as the eno field is auto increment total row never be duplicate, but the records are duplicates. How can I prevent inserting those duplicate records?
I tried using INSERT IGNORE AND ON DUPLICATE KEY UPDATE (I think I have not used them properly).
The way I used them is,
mysql> insert into emp(ename,dno,mgr,sal) values('dlksdgj',2,2,2000);
Query OK, 1 row affected (0.03 sec)
mysql> insert ignore into emp(ename,dno,mgr,sal) values('dlksdgj',2,2,2000);
Query OK, 1 row affected (0.03 sec)
mysql> insert into emp(ename,dno,mgr,sal) values('dlksdgj',2,2,2000) ON DUPLICATE KEY UPDATE eno=eno;
Query OK, 1 row affected (0.03 sec)
mysql> insert into emp(ename,dno,mgr,sal) values('dlksdgj',2,2,2000) ON DUPLICATE KEY UPDATE eno=eno;
Query OK, 1 row affected (0.04 sec
mysql> desc emp;
+-------+-------------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+-------+-------------+------+-----+---------+----------------+
| eno | int(11) | NO | PRI | NULL | auto_increment |
| ename | varchar(50) | YES | | NULL | |
| dno | int(11) | YES | | NULL | |
| mgr | int(11) | YES | MUL | NULL | |
| sal | int(11) | YES | | NULL | |
+-------+-------------+------+-----+---------+----------------+
alter the table by adding UNIQUE constraint
ALTER TABLE employee ADD CONSTRAINT emp_unique UNIQUE (ename,dno,mgr,sal)
but you can do this if the table employee is empty.
or if records existed, try adding IGNORE
ALTER IGNORE TABLE employee ADD CONSTRAINT emp_unique UNIQUE (ename,dno,mgr,sal)
UPDATE 1
Something went wrong, I guess. You only need to add unique constraint on column ename since eno will always be unique due to AUTO_INCREMENT.
In order to add unique constraint, you need to do some cleanups on your table.
The queries below delete some duplicate records, and alters table by adding unique constraint on column ename.
DELETE a
FROM Employee a
LEFT JOIN
(
SELECT ename, MIN(eno) minEno
FROM Employee
GROUP BY ename
) b ON a.eno = b.minEno
WHERE b.minEno IS NULL;
ALTER TABLE employee ADD CONSTRAINT emp_unique UNIQUE (ename);
Here's a full demonstration
SQLFiddle Demo
Create a UNIQUE CONSTRAINT on which you think the duplicacy exist .
like
ALTER TABLE MYTABLE ADD CONSTRAINT constraint1 UNIQUE(column1, column2, column3)
This will work regardless of whether you clean up your table first (i.e. you can stop inserting duplicates immediately and clean up on separate schedule) and without having to add any unique constraints or altering table in any other way:
INSERT INTO
emp (ename, dno, mgr, sal)
SELECT
e.ename, 2, 2, 2000
FROM
(SELECT 'dlksdgj' AS ename) e
LEFT JOIN emp ON e.ename = emp.ename
WHERE
emp.ename IS NULL
The above query assumes you want to use ename as a "unique" field, but in the same way you could define any other fields or their combinations as unique for the purposes of this INSERT.
It works because it's an INSERT ... SELECT format where the SELECT part only produces a row (i.e. something to insert) if its left joined emp does not already have that value. Naturally, if you wanted to change which field(s) defined this "uniqueness" you would modify the SELECT and the LEFT JOIN accordingly.