why this result use column of parent table in subquery - mysql

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.

Related

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;

Auto numerate MySQL Query

Is there any mysql query, to update a table and set numbers starting from 1?
For example, the table "item" has 100000 rows, the query would just update first row and set id ="1", next to 2, 3, 4 etc.
Try:
ALTER TABLE item MODIFY id INT PRIMARY KEY NOT NULL AUTO_INCREMENT
If you have id in your item table.
But it will show error on id column having duplicate values.
add auto increment column (INT) and it should do what you want
Is there already a primary key in the table? If not then create one with AUTO_INCREMENT.
This would do the job done.
ALTER TABLE `your_table`
ADD COLUMN `id_primary` int NOT NULL AUTO_INCREMENT FIRST ,
ADD PRIMARY KEY (`id_primary`);
Note: Changing an existing column to primary key AUTO_INCREMENT would raise error if that column contains duplicate values.
Given this
MariaDB [sandbox]> select * from posts;
+------+--------+----------+
| id | userid | category |
+------+--------+----------+
| NULL | 1 | a |
| NULL | 1 | b |
| NULL | 1 | c |
| NULL | 2 | a |
| NULL | 1 | a |
+------+--------+----------+
5 rows in set (0.00 sec)
This code
use sandbox;
update posts p,(select #rn:=0) rn
set id=(#rn:=#rn+1)
where 1 = 1;
Results in
MariaDB [sandbox]> select * from posts;
+------+--------+----------+
| id | userid | category |
+------+--------+----------+
| 1 | 1 | a |
| 2 | 1 | b |
| 3 | 1 | c |
| 4 | 2 | a |
| 5 | 1 | a |
+------+--------+----------+
5 rows in set (0.00 sec)

Creating an Associative entity in 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>

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.

Deleting duplicate rows, no unique keys - relational table

I have a relational table that connects two other tables based on their IDs. There can be duplicates for both columns - but there CANNOT be the same row twice. I handle the checking code side.
How do I remove duplicate rows (see below):
select * from people:
a | b
1 2
1 3
1 3
1 7
2 3
2 5
2 5
2 9
I want the result to be:
a | b
1 2
1 3
1 7
2 3
2 5
2 9
This should work:
ALTER IGNORE TABLE people ADD UNIQUE (a,b);
If you don't want to add an index, then this should work:
DROP TABLE IF EXISTS people_old;
DROP TABLE IF EXISTS people_new;
CREATE TABLE people_new LIKE people;
INSERT INTO people_new SELECT DISTINCT * FROM people;
RENAME TABLE people TO people_old, people_new TO people;
There can be duplicates for both columns - but there CANNOT be the same row twice
That's a constraint on the table that you have not implemented. The constraint is a unique index on (a,b). If you had the index you would not have duplicates.
IMHO your best approach is to add the unique index to the table, using a temporary table to first remove the duplicates:
Copy person to person_temp
Delete all from person
Add unique index to person
Copy unique a,b from person_temp to `person.
This is how you can delete duplicate rows... I'll write you my example and you'll need to apply to your code. I have Actors table with ID and I want to delete the rows with repeated first_name
mysql> select actor_id, first_name from actor_2;
+----------+-------------+
| actor_id | first_name |
+----------+-------------+
| 1 | PENELOPE |
| 2 | NICK |
| 3 | ED |
....
| 199 | JULIA |
| 200 | THORA |
+----------+-------------+
200 rows in set (0.00 sec)
-Now I use a Variable called #a to get the ID if the next row have the same first_name(repeated, null if it's not).
mysql> select if(first_name=#a,actor_id,null) as first_names,#a:=first_name from actor_2 order by first_name;
+---------------+----------------+
| first_names | #a:=first_name |
+---------------+----------------+
| NULL | ADAM |
| 71 | ADAM |
| NULL | AL |
| NULL | ALAN |
| NULL | ALBERT |
| 125 | ALBERT |
| NULL | ALEC |
| NULL | ANGELA |
| 144 | ANGELA |
...
| NULL | WILL |
| NULL | WILLIAM |
| NULL | WOODY |
| 28 | WOODY |
| NULL | ZERO |
+---------------+----------------+
200 rows in set (0.00 sec)
-Now we can get only duplicates ID:
mysql> select first_names from (select if(first_name=#a,actor_id,null) as first_names,#a:=first_name from actor_2 order by first_name) as t1;
+-------------+
| first_names |
+-------------+
| NULL |
| 71 |
| NULL |
...
| 28 |
| NULL |
+-------------+
200 rows in set (0.00 sec)
-the Final Step, Lets DELETE!
mysql> delete from actor_2 where actor_id in (select first_names from (select if(first_name=#a,actor_id,null) as first_names,#a:=first_name from actor_2 order by first_name) as t1);
Query OK, 72 rows affected (0.01 sec)
-Now lets check our table:
mysql> select count(*) from actor_2 group by first_name;
+----------+
| count(*) |
+----------+
| 1 |
| 1 |
| 1 |
...
| 1 |
+----------+
128 rows in set (0.00 sec)
it works, if you have any question write me back