## Basic Command
```sql
-- Create Table
CREATE TABLE
users (
user_id BIGINT UNSIGNED PRIMARY KEY AUTO_INCREMENT,
username CHAR(10) NOT NULL UNIQUE,
email VARCHAR(50) NOT NULL,
gender ENUM('Male', 'Female'),
intersets SET(
'Technology',
'Sports',
'Music',
'Art',
'Travel',
'Food',
'Fashion',
'Science'
) NOT NULL,
bio TEXT NOT NULL,
profile_picture TINYBLOB,
age TINYINT UNSIGNED NOT NULL,
is_admin BOOLEAN DEFAULT FALSE NOT NULL,
balance FLOAT DEFAULT 0.0 NOT NULL,
joined_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP NOT NULL,
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP NOT NULL,
birth_date DATE NOT NULL,
bed_time TIME NOT NULL,
graduation_year YEAR NOT NULL
CONSTRAINT chk_age CHECK(age<100),
CONSTRAINT uq_email UNIQUE(email)
);
-- Insert element
INSERT INTO
users (
username,
email,
gender,
intersets,
bio,
age,
is_admin,
birth_date,
bed_time,
graduation_year
)
VALUES
(
'mr.nobody',
'
[email protected]',
'Male',
'Travel,Food,Technology',
'I like traveling and eating',
88,
TRUE,
'1999.05.08',
'22:30',
'1976'
);
-- drop column
ALTER TABLE users DROP COLUMN profile_picture;
-- change column
ALTER TABLE users CHANGE COLUMN bio abuot_me TINYTEXT;
-- modify column
ALTER TABLE users MODIFY COLUMN;
-- remane database
ALTER TABLE users RENAME TO customers;
ALTER TABLE customers RENAME TO users;
-- drop constraints
ALTER TABLE users DROP CONSTRAINT uq_email;
ALTER TABLE users DROP CONSTRAINT username;
-- adding constraints
ALTER TABLE users
ADD CONSTRAINT uq_eamil UNIQUE(email),
ADD CONSTRAINT uq_username UNIQUE(username)
-- add or remove a NULL constraint
ALTER TABLE users MODIFY bed_time TIME NULL;
ALTER TABLE users MODIFY bed_time TIME NOT NULL;
-- Change column date type
ALTER TABLE users ADD COLUMN grduation_date DATE NOT NULL DEFAULT MAKEDATE(graduation_year, 1);
-- SHOW CURRENT TABLE design
SHOW CREATE TABLE users;
```
## GENERATED COLUMNS
- GENERATED : 특정 값을 토대로 연산을 통해 만들어진 값을 만들어준다.
- STORED : 실제로 값이 데이터로 저장된다.
- VIRTUAL : 컬럼을 불러올 떄 자동으로 **연산**되어 보여진다.(저장X)
```sql
CREATE TABLE
users_v2 (
user_id BIGINT UNSIGNED PRIMARY KEY AUTO_INCREMENT,
first_name VARCHAR(50),
last_name VARCHAR(50),
email VARCHAR(100),
full_name VARCHAR(101) GENERATED ALWAYS AS (CONCAT(first_name, ' ', last_name)) STORED
);
ALTER TABLE users_v2 ADD COLUMN email_domain VARCHAR(50) GENERATED ALWAYS AS(SUBSTRING_INDEX(email, '@', -1)) virtual;
SELECT *
FROM users_v2;
```
## FOREIGN KEY
```sql
CREATE TABLE
dogs (
dog_id BIGINT UNSIGNED PRIMARY KEY AUTO_INCREMENT,
name VARCHAR(50) NOT NULL,
date_of_birth DATE,
weight DECIMAL(5, 2),
owner_id BIGINT UNSIGNED,
breed_id BIGINT UNSIGNED DEFAULT 2,
-- ON DELETE CASCADE
-- ON DELETE SET NULL -> NOT NULL(X)
-- ON DELETE SET DEFAULT
CONSTRAINT owner_fk FOREIGN KEY (owner_id) REFERENCES owners (owner_id) ON DELETE SET NULL,
CONSTRAINT breed_fk FOREIGN KEY (breed_id) REFERENCES breeds (breed_id) ON DELETE SET DEFAULT
);
ALTER TABLE dogs DROP FOREIGN KEY owner_fk;
```
### Relationship
#### 1:N OR N:1
```sql
CREATE TABLE
owners (
owner_id BIGINT UNSIGNED PRIMARY KEY AUTO_INCREMENT,
name VARCHAR(50) NOT NULL,
email VARCHAR(100) UNIQUE,
phone VARCHAR(20),
address TINYTEXT
);
CREATE TABLE
breeds (
breed_id BIGINT UNSIGNED PRIMARY KEY AUTO_INCREMENT,
name VARCHAR(50) NOT NULL,
size_category ENUM('small', 'medium', 'big') DEFAULT 'small',
typical_lifespan TINYINT
);
```
#### 1:1
```sql
CREATE TABLE
pet_passports (
pet_id BIGINT UNSIGNED PRIMARY KEY AUTO_INCREMENT,
blood_type VARCHAR(10),
allergies TEXT,
last_checkup_date DATE,
dog_id BIGINT UNSIGNED UNIQUE,
FOREIGN KEY dog_id REFERENCES dogs (dog_id) ON DELETE CASCADE
);
```
#### N:N
```sql
CREATE TABLE
tricks (
trick_id BIGINT UNSIGNED PRIMARY KEY AUTO_INCREMENT,
name VARCHAR(50) UNIQUE NOT NULL,
difficulty ENUM('easy', 'medium', 'hard') NOT NULL DEFAULT 'easy'
);
-- Bridge TABLE
CREATE TABLE
dog_tricks (
dog_id BIGINT UNSIGNED,
trick_id BIGINT UNSIGNED,
proficiency ENUM('beginner', 'intermediate', 'expert') NOT NULL DEFAULT 'beginner',
date_learned TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
PRIMARY KEY (dog_id, trick_id),
FOREIGN KEY (dog_id) REFERENCES dogs (dog_id) ON DELETE CASCADE,
FOREIGN KEY (trick_id) REFERENCES tricks (trick_id) ON DELETE CASCADE
);
```
## EVENT
```sql
CREATE TABLE archived_movies LIKE movies;
TRUNCATE TABLE archived_movies;
DROP EVENT archived_old_movies;
CREATE EVENT archived_old_movies
ON SCHEDULE EVERY 2 MINUTE
STARTS CURRENT_TIMESTAMP + INTERVAL 2 MINUTE
DO
BEGIN
INSERT INTO archived_movies
SELECT * FROM movies
WHERE release_date < YEAR(CURDATE()) - 20;
DELETE FROM movies WHERE release_date < YEAR(CURDATE()) - 20;
END;
```
## TRIGGER
```sql
-- BEFORE : INSERT, UPDATE, DELETE
-- AFTER : INSERT, UPDATE, DELETE
SHOW TRIGGERS;
DROP TRIGGER after_movie_update;
TRUNCATE records;
CREATE TRIGGER after_movie_update
AFTER UPDATE
ON movies
FOR EACH ROW
BEGIN
DECLARE changes TINYTEXT DEFAULT '';
IF NEW.title <> OLD.title THEN SET changes = CONCAT('title changed ', OLD.title, '->', new.title, '\n');
END IF;
IF NEW.budget <> OLD.budget THEN SET changes = CONCAT(changes, 'Budget changed ', old.budget, '->', new.budget);
END IF;
INSERT INTO records (changes) VALUES (changes);
END;
```
## SELECT
- `SELECT (column 명) FROM (table)` : 특정 Column 값을 보여준다.
- `Table`의 모든 `Column`을 출력할려면 `*` 기호를 사용하면 된다.
- **Table의 값이 출력하지 않더라도 SELECT를 사용하기 위해선 TABLE을 꼭 명시에 주어야 한다.**
- 만약 테이블이 주어지지 않는다면 `SQL`에서 기본으로 제공하는 `information_schema.tables`을 사용할 수 있다.
```SQL
SELECT *
FROM information_schema.tables
```
## WHERE
- `WHERE 조건` : Column 안에서 특정 값만 추출 할 때 사용한다.
- 조건(>, >=, =, AND, OR, NOT )등이 있다.
### BETWEEN
- `BETWEEN`을 통해 `<= AND <=` 을 간결하게 표현 가능하다.
```SQL
SELECT *
FROM Customers
WHERE CustomerID BETWEEN 10 AND 20
```
### LIKE
- `LIKE`을 통해 문자열의 패턴을 검색할 수 있다.
- EX) 'KO_' -> 하나의 문자만 해당되는
- EX) 'KO%' -> 모든 문자만 해당되는
```SQL
SELECT *
FROM Customers
WHERE Country LIKE 'New%'
```
### RLIKE (Regular like)
- 문자열 패턴을 정규표현식으로 표현하여 비교한다.
#### 정규표현식
- `a-z` : 소문자 알파벳
- `A-Z`: 대문자 알파벳
- `^` : 정규 표현식 시작 표시
- `[]` : 범위 설정
- `+` : 조건 잇기
- `
: 정규 표현식 종료 표시 (**설정 하지 않으면 뒤에 문자열이 추가될 수 있음**)
- `*` : 직전의 조건 범위를 충족하는 문자의 개수가 0개 이상이다.
- `\\` : 이스케이프 문자
```sql
SELECT user_id, name, mail
FROM Users
WHERE mail RLIKE '^[a-zA-Z][a-zA-Z0-9_.-]*+@leetcode\\.com
```
### IN
- `IN`을 통해 여러 이산 값 조건을 할 수 있다. (특정 값들 중 하나인지 아닌지 판단한다)
- [[MySQL#Sub Query|Sub Query]]의 조건을 걸기 위해 사용할 경우 순서가 **Sub Query -> Main Query**이다.
```SQL
SELECT *
FROM Customers
WHERE Country = IN('New york', 'London', 'Vancouver')
```
### EXISTS *
- [[MySQL#Sub Query|Sub Query]]에 데이터가 존재하는지 체크하고 **존재할 경우 TRUE를 반환**한다.
- 순서는 **Main Query -> Sub Query**이다.
## Sub Query
- `Sub Query`를 추가해 조건을 넣을 수 있다.
- **단 서브 쿼리의 결과가 둘 이상**이라면 **IN이나 EXISTS, ANY, ALL**등을 사용하여 한다.
```SQL
SELECT *
FROM Customers
WHERE Country = (SELECT Country FROM Customers WHERE CustomerID = 30)
```
### ANY
- `Sub Query`의 결과 값 중 어떤 것이든 만족시키는 값을 찾을 때 사용한다.
```SQL
SELECT *
FROM Customers
WHERE Country > ANY (SELECT Country FROM Customers WHERE CustomerID > 30)
```
### ALL
- `Sub Query`의 모든 결과값을 만족시키는 값을 찾을 때 사용한다..
```SQL
SELECT *
FROM Customers
WHERE CustomerID > ALL (SELECT CustomerID FROM Customers WHERE Country = 'Germany')
```
## AS
- `Column` 명이나 `Sub Query`명 등 여러 이름을 지정할 때 사용한다.
- [[MySQL#SELECT|SELECT]] `Column` 명을 바꾸면 이를 출력할 때 `Column 제목`이 바뀐다.
```SQL
SELECT CustomerID AS ID
FROM Customers
```
## ORDER BY
- `특정 Column`을 기준으로 정렬하여 출력 할 수 있다.
- ASC : 오름차순(생략가능), DESC : 내림차순
```SQL
SELECT *
FROM Customers
ORDER BY ID DESC, Country
```
## CASE WHEN THEN ELSE END
- `Column`의 값을 조건에 맞춰 특정 값로 바꿔 출력하려 할 때 사용한다.
- `CASE`와 `END` 형식을 취하며
- `WHEN`으로 조건으로 걸고 해당 조건이 맞으면 `THEN`으로 원하는 값을 출력한다.
- `WHEN`은 여러 번 사용할 수 있으며 모든 조건이 맞지 않을 시 `ELSE`에 있는 값이 출력된다.
```SQL
SELECT BOARD_ID, WRITER_ID, TITLE, PRICE,
CASE
WHEN STATUS = 'SALE' THEN '판매중'
WHEN STATUS = 'RESERVED' THEN '예약중'
ELSE '거래완료'
END AS STATUS
FROM USED_GOODS_BOARD
WHERE CREATED_DATE = '2022-10-05'
ORDER BY BOARD_ID DESC;
```
## DISTINCT
- `전체 Column`의 중복된 내용을 제거한다.
```SQL
SELECT DISTINCT CustomerID, Country
FROM Customers
ORDER BY Country
```
## LIMIT
- `상위 N`개만 선별한다.
- [[MySQL#ORDER BY|ORDER BY]]와 결합하여 **최대 값**이나 **최소 값**을 가져올 수 있다.
```SQL
SELECT DISTINCT Country
FROM Customers
ORDER BY Country DESC
LIMIT 5
```
## GROUP BY
- 같은 Column 값들 끼리 묶어서 보여준다.
- **다른 Column 값**을 보기 위해선 **집계 함수**를 사용해야 한다.
- AVG() : 평균
- MAX() : 최대값
- MIN() : 최소값
- COUNT() : 개수
- COUNT(DISTINCT) : 중복 제외 개수
- STDEV(): 표준편차
- VARIANCE(): 분산
```SQL
SELECT City, MAX(CustomerID) AS AVERage
FROM Customers
GROUP BY City
```
- 만약 `GROUP`으로 묶이지 않은 다른 값을 출력하려 한다면 오류가 발생한다.
### GROUP_CONCAT
- `GROUP`별로 문자를 합칠 때 사용한다.
```sql
SELECT sell_date, COUNT(DISTINCT product) AS num_sold, GROUP_CONCAT(DISTINCT PRODUCT ORDER BY PRODUCT) AS products
FROM Activities
GROUP BY sell_date
```
### HAVING
- [[MySQL#WHERE|WHERE]]과 비슷한 개념으로 조건을 제한한다.
- **집계 함수**에 대해서 조건 제한하는 개념이다.
- 여러 Column의 조합의 조건으로 Table을 조회하기 위해서는 **GROUP BY와 HAVING을 사용해야 한다.**
- **반드시** `GROUP BY` 뒤에 나와야 한다.
```SQL
SELECT City, MAX(CustomerID) AS MAXid
FROM Customers
GROUP BY City
HAVING MAX(CustomerID) > 20
```
## PARTITION BY *
PARTITION을 이용해 그룹 안 값 관리하기
```SQL
SELECT
MAX(CASE WHEN OCCUPATION = 'Doctor' THEN NAME END),
MAX(CASE WHEN OCCUPATION = 'Professor' THEN NAME END),
MAX(CASE WHEN OCCUPATION = 'Singer' THEN NAME END),
MAX(CASE WHEN OCCUPATION = 'Actor' THEN NAME END)
FROM (
SELECT *, RANK() OVER (PARTITION BY OCCUPATION ORDER BY NAME) RN
FROM OCCUPATIONS
) AS TEMP
GROUP BY RN
```
## IFNULL
- `IFNULL(COLUMN, 대채 값)`을 통해 `COLUMN` 값이 `NULL`일 때 다른 값을 반환할 수 있다.
```SQL
SELECT IFNULL(City, "EMPTY")
FROM Customers
```
## ROW_NUMBER
- `Coulmn`의 값을 순차적으로 번호를 매길 때 사용한다.
- `OVER(ORDER BY 정렬)`과 함께 써서 어떠한 순서대로 번호를 매길지 정해야 한다.
```SQL
SELECT City, ROW_NUMBER() OVER(ORDER BY CustomerID)
FROM Customers
```
## RANK
- `Coulmn`의 값을 순차적으로 랭킹을 매길 때 사용한다.
- `OVER(ORDER BY 정렬)`과 함께 써서 어떠한 순서대로 랭킹을 매길지 정해야 한다.
`RNAK()` : 순차적으로 번호 부여(동일 번호 다음엔 순위를 건너뛰고 부여)
`DENSE_RANK()` : 순차적으로 번호 부여(동일 번호 다음엔 다음 순위 부여)
`PERCENT_RANK()` : 순차적으로 상위 % 부여
```SQL
SELECT ROUND(AVG(A.LAT_N), 4)
FROM (
SELECT LAT_N, PERCENT_RANK() OVER(ORDER BY LAT_N) AS P_RANK
FROM STATION
) AS A
WHERE A.P_RANK = 0.5
```
## SET
- `SET`을 통해 변수 설정할 수 있다.
- 변수 명은 `@`가 들어가야 한다.
- `SET` 끝에는 `;`이 들어가야 한다.
- 변수 안에 값을 넣을 때는 `:=`을 사용하여야 한다.
```SQL
SET @hour = -1;
SELECT (@hour := @hour+1) AS HOUR, (
SELECT COUNT(*)
FROM ANIMAL_OUTS
WHERE HOUR(DATETIME) = @hour
) AS COUNT
FROM ANIMAL_OUTS
WHERE @hour < 23
ORDER BY HOUR
```
## JOIN *
### INNER JOIN
### LEFT JOIN
### RIGHT JOIN
## UNION *
## RECURSIVE
- `RECURSIVE`을 활용하여 특정 `Table`을 반복시켜 변환할 수 있다.
- [[MySQL#UNION|UNION]]을 통해 합쳐나가야 하며 **더 이상 합쳐지지 못할 때(NULL)** 재귀가 끝난다.
```SQL
WITH RECURSIVE GENERATIONS AS (
SELECT ID, PARENT_ID, 1 AS GENERATION
FROM ECOLI_DATA
WHERE PARENT_ID IS NULL
UNION ALL
SELECT C.ID, C.PARENT_ID, G.GENERATION+1
FROM GENERATIONS AS G
JOIN ECOLI_DATA AS C
ON G.ID = C.PARENT_ID
)
SELECT COUNT(*) AS COUNT, A.GENERATION
FROM GENERATIONS AS A
WHERE A.ID NOT IN(
SELECT DISTINCT B.PARENT_ID
FROM GENERATIONS AS B
WHERE B.PARENT_ID IS NOT NULL
)
GROUP BY A.GENERATION
ORDER BY A.GENERATION
```
## MYSQL 내장 함수
### 문자열 함수
- `LENGTH()` : 문자열 길이 반환한다.
- `CONCAT('a','b','c')` : 여러 문자열을 합친다. 만약 넣은 문자열 중 하나라도 `NULL`이면 `NULL`을 반환한다.
- `LOCATE('target', 'string')` : 첫 번째 문자열이 두 번째 문자열의 어느 번째에 있는지 알려준다. (**인덱스가 1부터 시작임**)
- `LEFT('string', 'int')`, `RIGHT('string', 'int')` : 왼쪽, 오른쪽에서 지정한 개수 만큼 추출함.
- `LOWER()`, `UPPER()` : 대소문자로 변환한다.
- `REPLACE('string1', 'string2', 'string3')` : 첫 번째 문장 중 두 번째 문자를 찾아 세 번째로 바꾼다.
- `TRIM()` : 특정 문자열을 제거한다. (기본 설정 양쪽)
- `TRIM(LEADING 'target' FROM 'string')` : 문자열의 앞쪽에 있는 특정 문자열을 제거한다.
- `TRIM(TRALING 'target' FROM 'string')` : 문자열의 뒤쪽에 있는 특정 문자열을 제거한다.
- `FORMAT(string, point)` : 데이터를 세 자리마다 쉼표를 사용하는 형식으로 변환 (**point는 소수점을 어느자리까지 표헌할지 정함**)
- `SUBSTRING(string, position, length)` : 해당 문장의 position위치에서 지정한 길이(length)까지 부분 문자열을 반환한다.
- `REPEAT(string, length)` : 해당 문장을 길이만큼 반복해 반환한다.
### 수학 함수
- `FLOOR()` : 내림
- `CEIL()` : 올림
- `ROUND(n1,n2)` : 반올림 (n2 : 소수점 몇자리 기준으로 반올림 할지 정한다.)
- `TRUNCATE(숫자,버릴 자릿수)` : 숫자를 버릴 자릿수 아래로 버림(-일 경우 정수자리수 부분이다.)
- `SQRT()` : 양의 제곱근
- `POW(n1,n2)` : 첫 번째 수로 밑 두 번째 수가 지수
- `EXP()` : e의 거듭제곱값
- `LOG()` : 자연로그값
- `PI()` : 파이값
- `SIN()` : 사인값
- `COS()` : 코사인값
- `TAN()` : 탄젠트값
- `ABS()` : 절대값
- `RAND()` : 0.0보다 크거나 같고 1.0보다 작은 하나의 실수 무작위 생성
### 날짜 함수
- `NOW()` : 지금 날짜 반환(**YYYY-MM_DD HH:MM:SS로 변환**)
- `CURDATE()` : 지금 날짜 변환(**YYYY-MM_DD로 변환**)
- `CURTIME()` : 지금 시각 변환(**HH:MM:SS로 변환**)
- `DATE(DATE)` : 전달받은 값에 해당하는 날짜 정보 반환
- `YEAR(DATE)` : 전달받은 값에 해당하는 월 정보 반환
- `MONTH(DATE)` : 전달받은 값에 해당하는 월 정보 반환
- `HOUR(DATE)` : 전달받은 값에 해당하는 시간 정보 반환
- `MINUTE(DATE)` : 전달받은 값에 해당하는 분 정보 반환
- `SECOND(DATE)` : 전달받은 값에 해당하는 초 정보 반환
- `MONTHNAME(DATE)`: 월에 해당하는 이름 반환
- `DAYNAME(DATE)`: 날짜에 해당하는 요일 반환
- `DAYOFWEEK(DATE)` : 일자가 해당 주에 몇번째 날인지를 반환 (일요일 = 1, 토요일 = 7)
- `DAYOFMONTH(DATE)` : 일자가 해당 월에 몇 번째 날인지를 반환 (1~31)
- `DAYOFYEAR(DATE)` : 일자가 해당 연도에서 몇번째 날인지를 반환(1~366)
- `DATE_FORMAT(DATE, 'FORMAT')` : 특정 날짜를 포멧에 맞춰 출력
- `%Y` :4자리 년도 | `%y`: 2자리 년도
- `%m` : 숫자 월 ( 두자리 ) | `%M` : 긴 월(영문) | `%c` : 숫자 월(한자리는 한자리) | `%b` : 짧은 월(영문)
- `%d` : 일자 (두자리) | `%e` : 일자(한자리는 한자리)
- `%W` : 긴 요일 이름(영문) | `%a` : 짧은 요일 이름(영문)
- `%I` : 시간 (12시간) | `%H`: 시간(24시간)
- `%i` : 분
- `%S` : 초
- `%r` : hh:mm:ss AM,PM
- `%T` : hh:mm:SS
```SQL
SELECT DATE_FORMAT(NOW(),'%Y-%m-%d') AS DATE FROM DUAL
```
- `DATEDIFF(END_DATE, START_DATE)`로 두 DATE의 날짜 차이를 구할 수 있다.
- `EXTRACT(month FROM COLUMN)`로 해당 DATE의 원하는 값을 가져올 수 있다.
---
`FROM절/WHERE절 서브쿼리` `DISTINCT()` `like %` `COALESCE()` `IFNULL()` `DATE_FROMAT()` `CASE WHEN then ELSE` `LEFT()` `SUBSTR()` `JOIN` `UNION` `LIMIT` `TIMESTAMPDIFF()` `DISTINCT` `set` `REGEXP` `DATEDIFF` `RECURSIVE` `RIGHT()` `HAVING` `TRUNCATE()` `MID()` `ROUND()` `AVG()` `CONCAT()` `LPAD()` `RPAD()` `FLOOR()` `REPEAT` `REPLACE` `PARTITION BY` `RANK` `DENSE_RANK` `ROW_NUMBER` `CTE`, `GROUP_CONCAT`
```mysql
WITH sub1 AS (
SELECT Start_Date, RANK() OVER(ORDER BY Start_Date) AS R
FROM Projects
WHERE Start_Date NOT IN (SELECT End_Date FROM Projects)
), sub2 AS (
SELECT End_Date, RANK() OVER(ORDER BY End_Date) AS R
FROM Projects
WHERE End_Date NOT IN (SELECT Start_Date FROM Projects)
)
SELECT sub1.Start_Date, sub2.End_Date
FROM sub1
JOIN sub2 ON sub1.R = sub2.R
ORDER BY DATEDIFF(sub2.End_Date, sub1.Start_Date), sub1.Start_Date
```
```mysql
SET @NUM1 = 1;
SET @NUM2 = 1;
SELECT GROUP_CONCAT(NUM1 SEPARATOR '&')
FROM (
SELECT @NUM1 := @NUM1+1 AS NUM1
FROM information_schema.tables AS t1,information_schema.tables AS t2
) AS TEMP1
WHERE NUM1 <= 1000 AND NOT EXISTS (
SELECT *
FROM (
SELECT @NUM2 := @NUM2+1 AS NUM2
FROM information_schema.tables AS t1,information_schema.tables AS t2
LIMIT 1000
) AS TEMP2
WHERE MOD(NUM1, NUM2) = 0
AND NUM1 != NUM2
)
```