# ๐ŸŽˆ @์‹œ์ฝ” - MySQL ์ œ๋Œ€๋กœ ๋ฐฐ์šฐ๊ธฐ (inflearn)

์šฐ์„  mysql 8๋ฒ„์ „์„ ์„ค์น˜ (opens new window)ํ•ด์ฃผ๊ณ , ์„ค์น˜ ๊ณผ์ •์—์„œ custom ์„ ์„ ํƒํ•˜์—ฌ workbench๊นŒ์ง€ 8๋ฒ„์ „์œผ๋กœ ์„ค์น˜ํ•ด์ค€๋‹ค.

# Mysql ์‚ฌ์šฉ์ž

# mysql ์ ‘์†

C:\Users\๊ด€๋ฆฌ์ž>mysql -u root -p
Enter password: ************
Welcome to the MySQL monitor.  Commands end with ; or \g.
Your MySQL connection id is 34
Server version: 8.0.29 MySQL Community Server - GPL

Copyright (c) 2000, 2022, Oracle and/or its affiliates.

# ์‚ฌ์šฉ์ž ์กฐํšŒ

mysql> use mysql;
Database changed
mysql> select user, host from user;
+------------------+-----------+
| user             | host      |
+------------------+-----------+
| mysql.infoschema | localhost |
| mysql.session    | localhost |
| mysql.sys        | localhost |
| root             | localhost |
+------------------+-----------+
4 rows in set (0.00 sec)

# ์‚ฌ์šฉ์ž ์ถ”๊ฐ€/๊ถŒํ•œ๋ถ€์—ฌ

create user
mysql> create user <user-name>@'<host>' identified by '<password>';

mysql> create user 'test1234'@'localhost' identified by 'test1234';
Query OK, 0 rows affected (0.00 sec)

mysql> grant all privileges on test_database.* to test@'localhost';
Query OK, 0 rows affected (0.00 sec)

grant

mysql> grant all privileges on test_database.* to test_grant@'localhost' identified by 'test1234';
Query OK, 0 rows affected (0.00 sec)

localhost๋Œ€์‹ ์— %๋ฅผ ์‚ฌ์šฉํ•  ๊ฒฝ์šฐ ์™ธ๋ถ€์—์„œ๋„ ์ ‘์† ๊ฐ€๋Šฅํ•˜๋‹ค

mysql> grant all privileges on test_database.* to test_grant@'%' identified by 'test1234';
Query OK, 0 rows affected (0.01 sec)

์ ์šฉํ•˜๊ธฐ ํ•„์ˆ˜ !

mysql> flush privileges;

# ๋น„๋ฐ€๋ฒˆํ˜ธ ๋ณ€๊ฒฝ

mysql> use mysql;
Database changed
mysql> update user set password=PASSWORD('๋ณ€๊ฒฝํ•  ๋น„๋ฐ€๋ฒˆํ˜ธ') where user='์‚ฌ์šฉ์ž์ด๋ฆ„';
Query OK, 1 row affected (0.00 sec)
Rows matched: 1  Changed: 1  Warnings: 0

mysql> flush privileges;
Query OK, 0 rows affected (0.00 sec)

# ์‚ฌ์šฉ์ž ์‚ญ์ œ

mysql> delete from user where user='USER_ID'; 
mysql> flush privileges;
mysql> delete from user where user='test';
Query OK, 1 row affected (0.00 sec)

mysql> delete from user where user='test_grant';
Query OK, 2 rows affected (0.00 sec)

mysql> flush privileges;
Query OK, 0 rows affected (0.00 sec)

# database ์ƒ์„ฑ

mysql> show databases;
+--------------------+
| Database           |
+--------------------+
| information_schema |
| mysql              |
| performance_schema |
| sys                |
+--------------------+
4 rows in set (0.00 sec)

mysql> create database testdb;
Query OK, 1 row affected (0.02 sec)

mysql> show databases;
+--------------------+
| Database           |
+--------------------+
| information_schema |
| mysql              |
| performance_schema |
| sys                |
| testdb             |
+--------------------+
5 rows in set (0.00 sec)

# mysql workbench ์—ฐ๊ฒฐ

vuepress
vuepress
vuepress

# table ์ƒ์„ฑ

#๋ถ€์„œ
create table Dept(
	id tinyint unsigned not null auto_increment,
    pid tinyint unsigned not null default 0 comment '์ƒ์œ„๋ถ€์„œid',
    dname varchar(31) not null,
    PRIMARY KEY(id)
);

#์ง์›
create table Emp(
	id int unsigned not null auto_increment,
    ename varchar(31) not null,
    dept tinyint unsigned not null,
    salary int not null default 0 ,
    primary key(id),
    foreign key(dept) references Dept(id)
);

workbench์—์„œ refreshํ•ด์ค˜์•ผ ์ƒ์„ฑ๋œ ํ…Œ์ด๋ธ” ์กฐํšŒ ๊ฐ€๋Šฅ

vuepress

unsigned

๋ชจ๋“  Integerํƒ€์ž…๋“ค์€ UNSIGNED๋ฅผ ๊ฐ€์ง€๊ณ  ์žˆ๋‹ค.

ํ•ด๋‹น ์ปฌ๋Ÿผ์ด ์Œ์ˆ˜๊ฐ€ ์ ˆ๋Œ€ ๋  ์ผ์ด ์—†๋Š” ๊ฒฝ์šฐ, (auto-increment๋กœ primary key๋ฅผ ์žก์„ ๋•Œ์™€ ๊ฐ™์ด) ์ˆ˜์˜ ๋ฒ”์œ„๊ฐ€ ์–‘์ˆ˜ ์ชฝ์œผ๋กœ ๋” ๋„“์œผ๋ฉด ์ข‹์„ ๊ฒƒ์ด๋‹ค.
์ด๋•Œ ์‚ฌ์šฉํ•˜๋Š” ๊ฒŒ unsignedํƒ€์ž…์ด๋‹ค.

  • unsigned ์•„๋‹ ๋•Œ: -2147483648 ~ 2147483647
  • unsigned ์ผ ๋•Œ: 0 ~ 4294967295

# select/insert

#์ƒ์œ„๋ถ€์„œ
insert into Dept(pid, dname) values (0, '์˜์—…๋ถ€'), (0, '๊ฐœ๋ฐœ๋ถ€');

#ํ•˜์œ„๋ถ€์„œ
insert into Dept(pid, dname) 
values (1, '์˜์—…1ํŒ€'), (1, '์˜์—…2ํŒ€'), (1, '์˜์—…3ํŒ€'), (2, '์„œ๋ฒ„ํŒ€'), (2, 'ํด๋ผ์ด์–ธํŠธํŒ€');

# inner join

# ์ „์ฒด์กฐํšŒ

mysql> select * from Dept;
+----+-----+--------------+
| id | pid | dname        |
+----+-----+--------------+
|  1 |   0 | ์˜์—…๋ถ€       |
|  2 |   0 | ๊ฐœ๋ฐœ๋ถ€       |
|  3 |   1 | ์˜์—…1ํŒ€      |
|  4 |   1 | ์˜์—…2ํŒ€      |
|  5 |   1 | ์˜์—…3ํŒ€      |
|  6 |   2 | ์„œ๋ฒ„ํŒ€       |
|  7 |   2 | ํด๋ผ์ด์–ธํŠธํŒ€ |
+----+-----+--------------+
7 rows in set (0.00 sec)

# ํ•˜์œ„ ๋ถ€์„œ ์กฐํšŒ

mysql> select d1.dname as '์ƒ์œ„๋ถ€์„œ', d2.* from Dept d1 inner join Dept d2 on d1.id = d2.pid;
+----------+----+-----+--------------+
| ์ƒ์œ„๋ถ€์„œ | id | pid | dname        |
+----------+----+-----+--------------+
| ์˜์—…๋ถ€   |  3 |   1 | ์˜์—…1ํŒ€      |
| ์˜์—…๋ถ€   |  4 |   1 | ์˜์—…2ํŒ€      |
| ์˜์—…๋ถ€   |  5 |   1 | ์˜์—…3ํŒ€      |
| ๊ฐœ๋ฐœ๋ถ€   |  6 |   2 | ์„œ๋ฒ„ํŒ€       |
| ๊ฐœ๋ฐœ๋ถ€   |  7 |   2 | ํด๋ผ์ด์–ธํŠธํŒ€ |
+----------+----+-----+--------------+
5 rows in set (0.00 sec)

rand()

  • 0๊ณผ 1 ์‚ฌ์ด์˜ ๋‚œ์ˆ˜ ๋ฐœ์ƒ
mysql> select rand();
+--------------------+
| rand()             |
+--------------------+
| 0.3301079471875987 |
+--------------------+
1 row in set (0.00 sec)
  • 0~10 ์‚ฌ์ด์˜ ๋‚œ์ˆ˜ ํ•˜์—ฌ ์˜ฌ๋ฆผ์ฒ˜๋ฆฌ (0์ด ๋‚˜์˜ค์ง€ ์•Š๊ฒŒ ์˜ฌ๋ฆผ์œผ๋กœ ์ฒ˜๋ฆฌ)
mysql> select CEIL(rand() * 10);
+-------------------+
| CEIL(rand() * 10) |
+-------------------+
|                 3 |
+-------------------+
1 row in set (0.00 sec)

# function ์ƒ์„ฑ

vuepress
vuepress

function ์ƒ์„ฑ ์•ˆ ๋˜๋Š” ๊ฒฝ์šฐ

SET GLOBAL  log_bin_trust_function_creators=ON;

# 1. ํ•œ๊ธ€์ž๋ฅผ ๋žœ๋ค์œผ๋กœ ๋ฐ˜ํ™˜ํ•˜๋Š” ํ•จ์ˆ˜๋ฅผ ๋งŒ๋“ค์–ด๋ณด์ž.

CREATE FUNCTION `f_rand1` (_str varchar(255)) -- ๋งค๊ฐœ๋ณ€์ˆ˜๋Š” _
RETURNS varchar(31)
BEGIN
	declare v_ret varchar(31); -- ๋ณ€์ˆ˜๋Š” v_
    declare v_len tinyint;
    
    set v_len = char_length(_str); -- ํ•œ๊ธ€์€ 3๋ฐ”์ดํŠธ์ด๋ฏ€๋กœ char_lengthํ•˜๋ฉด ๊ธ€์ž์ˆ˜๋Œ€๋กœ ๊ธธ์ด ๋ฐ˜ํ™˜
    set v_ret = substring(_str, CEIL(rand() * v_len), 1); -- ๋‹จ์–ด์—์„œ 1๊ธ€์ž๋งŒ ๋žœ๋ค์œผ๋กœ ๋ฐ˜ํ™˜
RETURN v_ret;
END
mysql> select f_rand1('๊น€์ด๋ฐ•');
+-------------------+
| f_rand1('๊น€์ด๋ฐ•') |
+-------------------+
| ๊น€                |
+-------------------+
1 row in set (0.00 sec)

mysql> select f_rand1('1234567');
+--------------------+
| f_rand1('1234567') |
+--------------------+
| 7                  |
+--------------------+
1 row in set (0.00 sec)

mysql> select f_rand1('1234567');
+--------------------+
| f_rand1('1234567') |
+--------------------+
| 3                  |
+--------------------+
1 row in set (0.00 sec)

# 2. f_rand1ํ•จ์ˆ˜๋ฅผ ํ™œ์šฉํ•ด์„œ ์ด๋ฆ„์„ ๋งŒ๋“ค์–ด์ฃผ๋Š” ํ•จ์ˆ˜๋ฅผ ๋งŒ๋“ค์–ด๋ณด์ž.

CREATE FUNCTION `f_randname` ()
RETURNS varchar(31)
BEGIN
	declare v_ret varchar(31);
    declare v_lasts varchar(255) default '๊น€์ด๋ฐ•์กฐ์ตœ์ „์ฒœ๋ฐฉ์ง€๋งˆ์œ ๋ฐฐ์›'; -- ์„ฑ
    declare v_firsts varchar(255) default '์ˆœ์‹ ์„ธ์ข…์„ฑํ˜ธ์ง€ํ˜œ๊ฐ€์€์„ธํ˜ธ๋ฏผ๊ตญ๊ฐ€๋‚˜๋‹ค๋ผ๋งˆ๋ฐ”์‚ฌ์•„์ž์ฐจ๊ฒฐ์ฐฌ'; -- ์ด๋ฆ„
    
    set v_ret = concat(f_rand1(v_lasts), f_rand1(v_firsts), f_rand1(v_firsts));
RETURN v_ret;
END
mysql> select f_randname();
+--------------+
| f_randname() |
+--------------+
| ์œ ๊ฒฐ์€       |
+--------------+
1 row in set (0.00 sec)

mysql> select f_randname();
+--------------+
| f_randname() |
+--------------+
| ์›๋‹คํ˜ธ       |
+--------------+
1 row in set (0.00 sec)

# Procedure

# ์—ฌ๋Ÿฌ๋ช…์˜ ์ง์›์„ ํ”„๋กœ์‹œ์ €๋กœ ๋„ฃ์–ด๋ณด์ž.

vuepress

ํ•˜์œ„๋ถ€์„œ์— ์†ํ•˜๊ธฐ ์œ„ํ•ด

CREATE PROCEDURE `sp_test_emp` (_cnt int)
BEGIN
	declare v_idx int default 0;
    while v_idx < _cnt
    do
        -- ํ•˜์œ„๋ถ€์„œ์— ์†ํ•˜๊ธฐ ์œ„์— '34567', ๊ธ‰์—ฌ๋Š” *100ํ•˜์—ฌ `100~900`๊นŒ์ง€
		insert into Emp(ename, dept, salary) values (f_randname(), f_rand1('34567'), f_rand1('123456789') * 100);        
        set v_idx = v_idx + 1;
    end while;
END
mysql> call sp_test_emp(10);
Query OK, 1 row affected (0.02 sec)

mysql> select * from emp;
+----+--------+------+--------+
| id | ename  | dept | salary |
+----+--------+------+--------+
|  1 | ์ „์ฐจ์ข… |    7 |    100 |
|  2 | ๋งˆ๋ฏผ์ข… |    4 |    800 |
|  3 | ์กฐ์ž๋ผ |    6 |    500 |
|  4 | ์ตœํ˜ธ์ˆœ |    5 |    400 |
|  5 | ์กฐ์„ธํ˜ธ |    6 |    200 |
|  6 | ์ตœ๊ตญ์„ธ |    5 |    200 |
|  7 | ์กฐ์ฐจ๋งˆ |    7 |    500 |
|  8 | ๋ฐฉ์„ธ์ง€ |    3 |    700 |
|  9 | ์ „๊ฒฐ์€ |    3 |    100 |
| 10 | ์ด์„ธ์‚ฌ |    6 |    800 |
| 11 | ์ฒœ๋ฐ”๊ฐ€ |    5 |    300 |
| 12 | ์œ ํ˜œ์ข… |    6 |    400 |
+----+--------+------+--------+
12 rows in set (0.00 sec)

# group by

# ๋ถ€์„œ๋ณ„ ์ง์› ์ˆ˜ ์กฐํšŒ

mysql> select dept, count(*) from Emp group by dept;
+------+----------+
| dept | count(*) |
+------+----------+
|    3 |       62 |
|    4 |       47 |
|    5 |       47 |
|    6 |       55 |
|    7 |       51 |
+------+----------+
5 rows in set (0.00 sec)

# table ์ •๋ณด

mysql> desc Dept;
+-------+------------------+------+-----+---------+----------------+
| Field | Type             | Null | Key | Default | Extra          |
+-------+------------------+------+-----+---------+----------------+
| id    | tinyint unsigned | NO   | PRI | NULL    | auto_increment |
| pid   | tinyint unsigned | NO   |     | 0       |                |
| dname | varchar(31)      | NO   |     | NULL    |                |
+-------+------------------+------+-----+---------+----------------+
3 rows in set (0.00 sec)
mysql> show create table Dept;
+-------+-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| Table | Create Table                                                                                                                                                                                                                                                                        |
+-------+-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| Dept  | CREATE TABLE `dept` (
  `id` tinyint unsigned NOT NULL AUTO_INCREMENT,
  `pid` tinyint unsigned NOT NULL DEFAULT '0' COMMENT '์ƒ์œ„๋ถ€์„œid',
  `dname` varchar(31) NOT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=8 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci |
+-------+-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
1 row in set (0.00 sec)
mysql> show index from Dept;
+-------+------------+----------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+---------------+---------+------------+
| Table | Non_unique | Key_name | Seq_in_index | Column_name | Collation | Cardinality | Sub_part | Packed | Null | Index_type | Comment | Index_comment | Visible | Expression |
+-------+------------+----------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+---------------+---------+------------+
| dept  |          0 | PRIMARY  |            1 | id          | A         |           0 |     NULL |   NULL |      | BTREE      |         |               | YES     | NULL       |
+-------+------------+----------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+---------------+---------+------------+
1 row in set (0.00 sec)

mysql> show index from Emp;
+-------+------------+----------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+---------------+---------+------------+
| Table | Non_unique | Key_name | Seq_in_index | Column_name | Collation | Cardinality | Sub_part | Packed | Null | Index_type | Comment | Index_comment | Visible | Expression |
+-------+------------+----------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+---------------+---------+------------+
| emp   |          0 | PRIMARY  |            1 | id          | A         |           0 |     NULL |   NULL |      | BTREE      |         |               | YES     | NULL       |
| emp   |          1 | dept     |            1 | dept        | A         |           0 |     NULL |   NULL |      | BTREE      |         |               | YES     | NULL       |
+-------+------------+----------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+---------------+---------+------------+
2 rows in set (0.00 sec)

# table ๋ณต์ œ

# ๋ฐ์ดํ„ฐ๋นผ๊ณ  ๊ตฌ์กฐ๋งŒ ๋ณต์ œ

create table Dept2 like Dpet;

# ๋ฐ์ดํ„ฐ๊นŒ์ง€ ๋ณต์ œ

create table Dept3 AS select * from Dept;

WARNING

index๋Š” ์„ค์ •๋˜์ง€ ์•Š๋Š”๋‹ค..!
foriegn key์™€ ๊ฐ™์€ ์„ค์ •์€ ๋ณต์ œ๋˜์ง€ ์•Š์œผ๋ฏ€๋กœ ๋”ฐ๋กœ ์„ค์ •ํ•ด์ฃผ์–ด์•ผ ํ•จ.

# table ์ˆ˜์ •

-- on update: ๋ฐ์ดํ„ฐ ์ˆ˜์ •๋์„๋•Œ current_timestamp ์—…๋ฐ์ดํŠธ
alter table Dept add column workdate timestamp not null default current_timestamp on update current_timestamp;
mysql> select * from Dept;
+----+-----+---------+---------------------+
| id | pid | dname   | workdate            |
+----+-----+---------+---------------------+
|  1 |   0 | ์˜์—…๋ถ€  | 2022-04-27 14:17:46 |
|  2 |   0 | ๊ฐœ๋ฐœ๋ถ€  | 2022-04-27 14:17:46 |
|  3 |   1 | ์˜์—…1ํŒ€ | 2022-04-27 14:17:46 |
|  4 |   1 | ์˜์—…2ํŒ€ | 2022-04-27 14:17:46 |
|  5 |   1 | ์˜์—…3ํŒ€ | 2022-04-27 14:17:46 |
|  6 |   2 | ์„œ๋ฒ„ํŒ€  | 2022-04-27 14:17:46 |
|  7 |   2 | ํด๋ผํŒ€  | 2022-04-27 14:18:06 |
+----+-----+---------+---------------------+
7 rows in set (0.00 sec)

# ์•„๋ž˜์™€ ๊ฐ™์ด block์ฒ˜๋ฆฌํ•ด์„œ ์ˆ˜์ •ํ•˜๋Š” ์—ฐ์Šตํ•˜๊ธฐ

select * from Dept
-- update Dept set dname='ํด๋ผํŒ€'
where id = 7;

# truncate ๊ณผ delete ์ฐจ์ด

truncate์€ ํ…Œ์ด๋ธ”์„ ์ง€์› ๋‹ค๊ฐ€ ๋‹ค์‹œ ์ƒ์„ฑํ•˜๋Š” ๊ฑฐ๋‚˜ ๋‹ค๋ฆ„ ์—†๋‹ค. auto_increment๊ฐ€ 1๋ถ€ํ„ฐ ๋‹ค์‹œ ์‹œ์ž‘ํ•œ๋‹ค.

deleteํ•ด์„œ ๋ชจ๋“  ๋ฐ์ดํ„ฐ๋ฅผ ์ง€์šฐ๋ฉด auto_increment๊ฐ€ ์ด์ „ ๊ฐ’์—์„œ +1 ๋œ๋‹ค.

# TCL: Commit & Rollback

WARNING

Session ๋‹จ์œ„๋กœ Tx๋Š” ์ œ์–ด๋จ.

# autocommit ํ™•์ธ

select @@autocommit;
-- ๋ณ€๊ฒฝํ•˜๋Š” ๋ฐฉ๋ฒ• SET AUTOCOMMIT = FALSE; 

# ์—ฌ๋Ÿฌ๊ฐ€์ง€ ์ž‘์—…์„ ํ•  ๋•Œ, ๋ถˆ์•ˆํ•œ ๊ฒฝ์šฐ transcation์œผ๋กœ ์ž‘์—…ํ•ด์ค€๋‹ค.

start transaction; -- transaction ์‹œ์ž‘
select * from Dept where id in (1,2);
update Dept set dname='์˜์—…111' where id = 1;
commit; -- ์ ์šฉํ•˜๊ณ ํ”ˆ ๊ฒฝ์šฐ,
rollback; -- ์ทจ์†Œํ•˜๊ณ ํ”ˆ ๊ฒฝ์šฐ,

# savepoint

start transaction; -- transaction ์‹œ์ž‘

savepoint sp1; -- savepoint1 ์‹œ์ž‘
update Dept set dname='์˜์—…111' where id = 1;

savepoint sp2; -- savepoint2 ์‹œ์ž‘
update Dept set dname='๊ฐœ๋ฐœ111' where id = 2;

rollback to savepoint sp2; --sp2 ๋งŒ ๋กค๋ฐฑ

commit; -- ์ ์šฉ (sp1๋งŒ ์ ์šฉ๋จ)

# View

View๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ์ด์œ 

  • Security

    ๋ณด์•ˆ์„ ์œ„ํ•ด์„œ view๋ฅผ ๋งŽ์ด ์“ด๋‹ค. ํ…Œ์ด๋ธ” ํ…Œ์ดํ„ฐ๋ฅผ ์ˆ˜์ •ํ•˜์ง€ ๋ชปํ•˜๋„๋ก, ์‚ฌ์šฉ์ž ์ ‘๊ทผ ๊ถŒํ•œ์„ view ์กฐํšŒ๋งŒ ๊ฐ€๋Šฅํ•˜๋„๋ก ํ•˜๋Š” ๊ฒฝ์šฐ๊ฐ€ ์žˆ๋‹ค.

  • Simplicity

    ๋ณต์žกํ•œ ์ฟผ๋ฆฌ๋ฅผ ๋‹จ์ˆœํ•˜๊ฒŒ ํ•ด์ค€๋‹ค.

  • Performance

    ๋„คํŠธ์›Œํฌ ํŠธ๋ž˜ํ”ฝ์ด ์ค„์–ด๋“ค๊ณ , ์ปดํŒŒ์ผํ•˜๋Š” ์‹œ๊ฐ„๋„ ์ค„์–ด๋“ ๋‹ค.

# ์ƒ์„ฑ

์ƒ์„ฑ ์ฟผ๋ฆฌ๋Š” ์•„๋ž˜์™€ ๊ฐ™๊ณ , ์กฐํšŒ๋Š” ํ…Œ์ด๋ธ” ์กฐํšŒ์™€ ๋˜‘๊ฐ™์ด select๋กœ ์กฐํšŒํ•˜๋ฉด ๋œ๋‹ค.

create view v_Emp AS
select e.*, d.dname from Emp e inner join Dept d on e.dept = d.id;

vuepress

# view schema ์กฐํšŒ

mysql> select * from information_schema.views where table_schema = 'testdb';
+---------------+--------------+------------+----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+--------------+--------------+----------------+---------------+----------------------+----------------------+
| TABLE_CATALOG | TABLE_SCHEMA | TABLE_NAME | VIEW_DEFINITION                                                                                                                                                                                    | CHECK_OPTION | IS_UPDATABLE | DEFINER        | SECURITY_TYPE | CHARACTER_SET_CLIENT | COLLATION_CONNECTION |
+---------------+--------------+------------+----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+--------------+--------------+----------------+---------------+----------------------+----------------------+
| def           | testdb       | v_emp      | select `e`.`id` AS `id`,`e`.`ename` AS `ename`,`e`.`dept` AS `dept`,`e`.`salary` AS `salary`,`d`.`dname` AS `dname` from (`testdb`.`emp` `e` join `testdb`.`dept` `d` on((`e`.`dept` = `d`.`id`))) | NONE         | YES          | root@localhost | DEFINER       | utf8mb4              | utf8mb4_0900_ai_ci   |
+---------------+--------------+------------+----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+--------------+--------------+----------------+---------------+----------------------+----------------------+
1 row in set (0.00 sec)

# Trigger

ํŠน์ • ์กฐ๊ฑด์„ ๋งŒ์กฑํ•˜๋ฉด ์ €์ ˆ๋กœ ์‹คํ–‰๋œ๋‹ค.

DELIMITER //
Create Trigger <trigger-name>
    { BEFORE | AFTER } { INSERT | UPDATE | DELETE } -- ํŠน์ • ์ž‘์—… ์ˆ˜ํ–‰ ์ „/ํ›„ (๋ณดํ†ต ํ›„์— ๋งŽ์ด ํ•จ)
    { PRECEDES | FOLLOWS } other-trigger-name -- ๋‹ค๋ฅธ ํŠธ๋ฆฌ๊ฑฐ๊ฐ€ ๋˜ ์žˆ๋Š”๊ฒฝ์šฐ PRECEDES: otherํƒ€๊ธฐ์ „์— ํƒ€๋ผ / FOLLOWS: otherํƒ€๊ณ  ํƒ€๋ผ
    on <table-name> FOR EACH ROW
BEGIN
    ... OLD.<col>   ... NEW.<col>; -- OLD: update์ด์ „๊ฐ’ / NEW: update์ดํ›„๊ฐ’

END //
DELIMITER;

# ์šฐ์„  ๊ธฐ์กด Dept ํ…Œ์ด๋ธ”์— ์ง์› ์ˆ˜์ธ empcnt ์ปฌ๋Ÿผ์„ ์ถ”๊ฐ€ํ•ด์ฃผ๊ณ , ํ˜„์žฌ ์ง์›์ˆ˜๋กœ update ์ฒ˜๋ฆฌํ•ด์ฃผ์ž.

alter table Dept add column empcnt int not null default 0;
update Dept d set empcnt = (select count(*) from Emp where dept = d.id);

# Trigger ๋ฅผ ์ ์šฉํ•ด์ฃผ์ž.

CREATE DEFINER = CURRENT_USER TRIGGER `testdb`.`emp_AFTER_INSERT` AFTER INSERT ON `emp` FOR EACH ROW
BEGIN
  update Dept set empcnt = empcnt + 1
  where id = NEW.dept;
END

vuepress

# insert ํ•ด๋ณด๋ฉด Trigger๊ฐ€ ์ ์šฉ๋˜์–ด empcnt๊ฐ€ ๋Š˜์–ด๋‚˜๋Š” ๊ฑธ ํ™•์ธํ•  ์ˆ˜ ์žˆ๋‹ค.

mysql> select * from Dept;
+----+-----+---------+---------------------+---------+--------+
| id | pid | dname   | workdate            | captain | empcnt |
+----+-----+---------+---------------------+---------+--------+
|  1 |   0 | ์˜์—…111 | 2022-04-27 16:58:13 |    NULL |      0 |
|  2 |   0 | ๊ฐœ๋ฐœ๋ถ€  | 2022-04-27 16:57:39 |    NULL |      0 |
|  3 |   1 | ์˜์—…1ํŒ€ | 2022-04-28 10:23:20 |      66 |     62 |
|  4 |   1 | ์˜์—…2ํŒ€ | 2022-04-28 10:23:20 |     198 |     47 |
|  5 |   1 | ์˜์—…3ํŒ€ | 2022-04-28 13:52:15 |      76 |     48 |
|  6 |   2 | ์„œ๋ฒ„ํŒ€  | 2022-04-28 10:23:20 |    NULL |     55 |
|  7 |   2 | ํด๋ผํŒ€  | 2022-04-28 10:23:20 |     259 |     51 |
+----+-----+---------+---------------------+---------+--------+
7 rows in set (0.01 sec)

mysql> insert into Emp(ename, dept, salary) values ('SSS', 5, 200);
Query OK, 1 row affected (0.01 sec)

mysql> select * from Dept;
+----+-----+---------+---------------------+---------+--------+
| id | pid | dname   | workdate            | captain | empcnt |
+----+-----+---------+---------------------+---------+--------+
|  1 |   0 | ์˜์—…111 | 2022-04-27 16:58:13 |    NULL |      0 |
|  2 |   0 | ๊ฐœ๋ฐœ๋ถ€  | 2022-04-27 16:57:39 |    NULL |      0 |
|  3 |   1 | ์˜์—…1ํŒ€ | 2022-04-28 10:23:20 |      66 |     62 |
|  4 |   1 | ์˜์—…2ํŒ€ | 2022-04-28 10:23:20 |     198 |     47 |
|  5 |   1 | ์˜์—…3ํŒ€ | 2022-04-28 13:53:11 |      76 |     49 |
|  6 |   2 | ์„œ๋ฒ„ํŒ€  | 2022-04-28 10:23:20 |    NULL |     55 |
|  7 |   2 | ํด๋ผํŒ€  | 2022-04-28 10:23:20 |     259 |     51 |
+----+-----+---------+---------------------+---------+--------+
7 rows in set (0.00 sec)

# delete์—๋„ empcnt๊ฐ€ -1 ๋˜๋„๋ก trigger๋ฅผ ๊ฑธ์–ด์ค€๋‹ค.

CREATE DEFINER = CURRENT_USER TRIGGER `testdb`.`emp_AFTER_DELETE` AFTER DELETE ON `emp` FOR EACH ROW
BEGIN
 update Dept set empcnt = empcnt - 1
  where id = OLD.dept; -- ์ƒˆ๋กœ ๋“ค์–ด์˜ค๋Š” NEW๊ฐ€ ์—†์œผ๋ฏ€๋กœ OLD๋กœ ์จ์ค€๋‹ค.
END

# update์—๋„ ๊ฑธ์–ด์ค€๋‹ค. dept-์†ํ•œ ๋ถ€์„œ๊ฐ€ ์ˆ˜์ •๋˜๋Š” ๊ฒฝ์šฐ๋„ empcnt๋ฅผ ๋ณ€๊ฒฝํ•ด์ค˜์•ผํ•œ๋‹ค.

CREATE DEFINER=`root`@`localhost` TRIGGER `emp_AFTER_UPDATE` AFTER UPDATE ON `emp` FOR EACH ROW BEGIN
  IF OLD.dept != NEW.dept THEN -- ๋ถ€์„œ๊ฐ€ ๋ณ€๊ฒฝ๋˜๋Š” ๊ฒฝ์šฐ
    update Dept set empcnt = empcnt - 1
      where id = OLD.dept;
    
    update Dept set empcnt = empcnt + 1
      where id = NEW.dept;
  END IF;
END

# UNION

# UNION์€ ์ค‘๋ณต์„ ๋นผ๊ณ , UNION ALL์€ ์ค‘๋ณต๋„ ํฌํ•จํ•œ๋‹ค.

select * from subject where classroom < 3
{ UNION | UNION ALL}
select * from subject where classroom < 5

# @rownum

์ˆœ๋ฒˆ์„ ๋งค๊ธฐ๊ณ  ์‹ถ์„ ๋•Œ ์‚ฌ์šฉํ•œ๋‹ค.

mysql> select s.*, (@rownum := @rownum + 1)from Emp s, (select @rownum := 0) rn;
+-----+--------+------+--------+--------------------------+
| id  | ename  | dept | salary | (@rownum := @rownum + 1) |
+-----+--------+------+--------+--------------------------+
|   1 | ์ „์ฐจ์ข… |    7 |    100 |                        1 |
|   2 | ๋งˆ๋ฏผ์ข… |    4 |    800 |                        2 |
|   3 | ์กฐ์ž๋ผ |    6 |    500 |                        3 |
|   4 | ์ตœํ˜ธ์ˆœ |    5 |    400 |                        4 |
|   5 | ์กฐ์„ธํ˜ธ |    6 |    200 |                        5 |
|   6 | ์ตœ๊ตญ์„ธ |    5 |    200 |                        6 |
|   7 | ์กฐ์ฐจ๋งˆ |    7 |    500 |                        7 |
|   8 | ๋ฐฉ์„ธ์ง€ |    3 |    700 |                        8 |
|   9 | ์ „๊ฒฐ์€ |    3 |    100 |                        9 |
|  10 | ์ด์„ธ์‚ฌ |    6 |    800 |                       10 |
|  11 | ์ฒœ๋ฐ”๊ฐ€ |    5 |    300 |                       11 |
|  12 | ์œ ํ˜œ์ข… |    6 |    400 |                       12 |
|  13 | ์ฒœ๊ฐ€ํ˜ธ |    3 |    100 |                       13 |
|  14 | ์œ ์ฐจ์ˆœ |    5 |    300 |                       14 |
|  15 | ์œ ๊ฐ€์ข… |    6 |    100 |                       15 |
|  16 | ์ „์‚ฌ๋ฐ” |    4 |    400 |                       16 |
|  17 | ๊น€์ฐฌ์•„ |    3 |    100 |                       17 |
|  18 | ์›๊ฐ€์ฐฌ |    4 |    300 |                       18 |
|  19 | ๋งˆ์•„๊ฒฐ |    3 |    200 |                       19 |
...์ƒ๋žต

# Procudure - OUT ์ถœ๋ ฅ | into ์‚ฌ์šฉ

# ํ”„๋กœ์‹œ์ € ์ž‘์—… ํ›„, ๋ณ€์ˆ˜๋ฅผ ์ถœ๋ ฅํ•˜๊ณ  ์‹ถ์„ ๋•Œ OUT์„ ์‚ฌ์šฉํ•œ๋‹ค.

CREATE PROCEDURE `sp_emp_del`(_empid int, OUT _empcnt int) -- ์‚ญ์ œ ํ›„, empcnt ๊ฐ€์ ธ์˜ค๊ณ  ์‹ถ์„๋–„
BEGIN
  declare v_deptid tinyint;
  select dept into v_deptid from Emp where id = _empid; -- into: dept๋ฅผ v_deptid ๋ณ€์ˆ˜์— ์ž…๋ ฅ
  
  delete from Emp where id = _empid;
  
  select empcnt into _empcnt from Dept where id = v_deptid; 
END
call sp_emp_del(6, @empcnt); -- empcnt๋ฅผ ๋ฐ›์•„์˜จ๋‹ค.
select @empcnt;

Leave

Leave๋ฅผ ์‚ฌ์šฉํ•˜๋ฉด ํ”„๋กœ์‹œ์ € ๋„์ค‘ ์ค‘๋‹จ ๊ฐ€๋Šฅํ•˜๋‹ค.

CREATE DEFINER=`root`@`localhost` PROCEDURE `sp_emp_range`(_sid int, _eid int)
prox:BEGIN
    ... ์ƒ๋žต
    leave prox; -- ์กฐ๊ฑด ๋งŒ์กฑ ๋ชปํ–ˆ์„ ๋•Œ, ์ทจ์†Œ์‹œํ‚ค๊ณ  ์‹ถ์€ ๊ฒฝ์šฐ
END

# Prepare

# String์œผ๋กœ ๋ฐ›์•„์˜จ ๊ฐ’ ์ฟผ๋ฆฌ์— ์‚ฌ์šฉํ•˜๊ธฐ

CREATE PROCEDURE `sp_count`(_table varchar(31))
BEGIN
  SET @sql = CONCAT('select count(*) cnt from ', _table);
  
  PREPARE myQuery from @sql;
  EXECUTE myQuery;
  DEALLOCATE PREPARE myQuery; -- ๋ฉ”๋ชจ๋ฆฌ์—์„œ ์‚ญ์ œ
END

# Cursor

# row๋ฅผ ์„ ํƒํ•˜๋Š” ๊ฐœ๋…์ด๋ผ๊ณ  ๋ณด๋ฉด ๋œ๋‹ค.

vuepress

Declare <cursor-name> CURSOR FOR
    select ....
Declare Continue Handler
    For Not Found SET <end-flag> := True;

OPEN <cursor-name>;

    <cursor-loop-var>: LOOP
        Fetch <cursor-name> into <var-name>, ...;
        IF <end-flag> THEN
            LEAVE <cursor-loop-var>;
        END IF;
        ...
    END LOOP <cursor-loop-var>;

CLOSE <cursor-name>;

# Exception Handling

START TRANSACTION

DECLARE {EXIT | CONTINUE} HANDLER FOR [ SQLEXCEPTION | <code> ]

BEGIN
    SHOW ERRORS;
    SELECT '์—๋Ÿฌ๋ฐœ์ƒ' as 'Result';
    ROLLBACK;
END;

-- ์œ„์—์„œ CONTINUE ๋ผ๊ณ  ์„ ์–ธํ–ˆ๋‹ค๋ฉด, ์˜ค๋ฅ˜ ๋ฐœ์ƒํ•ด๋„ ์•„๋ž˜ ๊ณ„์† ์ˆ˜ํ–‰!

COMMIT;

# ์œ„ ๋‚˜์˜จ ๋‚ด์šฉ์„ ์ „๋ถ€ ์‚ฌ์šฉํ•œ Procedure ์˜ˆ์ œ

CREATE PROCEDURE `sp_emp_range`(_sid int, _eid int)
prox:BEGIN
  declare v_sid int default _sid;
  declare v_eid int default _eid;
  
  -- cursor ์ž„์‹œ ๋ณ€์ˆ˜
  declare v_empid int;
  declare v_ename varchar(31);
  declare v_dname varchar(31);
  
  -- cursor ์ข…๋ฃŒ flag
  Declare _done boolean default False;
  
  Declare _cur CURSOR FOR
    select id, ename, dname  from v_Emp where id between v_sid and v_eid;
    
  Declare Continue Handler
    For Not Found SET _done := True;
    
    
  -- error handling
  DECLARE EXIT HANDLER FOR SQLEXCEPTION
  BEGIN
    SHOW ERRORS;
    SELECT '์—๋Ÿฌ๋ฐœ์ƒ' as 'Result';
  END;
  
  IF _sid < 0 AND _eid < 0 THEN
    leave prox;
  END IF;
  
  IF _sid > _eid THEN
    set v_sid = _eid;
    set v_eid = _sid;
  END IF;
  
  -- ์ž„์‹œํ…Œ์ด๋ธ” ์กด์žฌํ•˜๋Š” ๊ฒฝ์šฐ drop
  drop temporary table IF Exists Tmp;
  
  -- ์ž„์‹œ ํ…Œ์ด๋ธ” ์ƒ์„ฑ
  create temporary table Tmp (
    empid int,
    edname varchar(63)
  );

  OPEN _cur; -- ์ปค์„œ ์—ด๊ธฐ
  
    cur_loop: LOOP
      Fetch _cur into v_empid, v_ename, v_dname;
      IF _done THEN
        LEAVE cur_loop;
      END IF;
      
      insert into Tmp(empid, edname) values(v_empid, concat(v_ename, '-', ifnull(v_dname,'์†Œ์†ํŒ€์—†์Œ')));
      
    END LOOP cur_loop;
  
  CLOSE _cur; -- ์ปค์„œ ๋‹ซ๊ธฐ
  
  select * from Tmp;
  
END
mysql> call sp_emp_range(5,1);
+-------+----------------+
| empid | edname         |
+-------+----------------+
|     1 | ์ „์ฐจ์ข…-ํด๋ผํŒ€  |
|     2 | ๋งˆ๋ฏผ์ข…-์˜์—…2ํŒ€ |
|     3 | ์กฐ์ž๋ผ-์„œ๋ฒ„ํŒ€  |
|     4 | ์ตœํ˜ธ์ˆœ-์˜์—…3ํŒ€ |
|     5 | ์กฐ์„ธํ˜ธ-์„œ๋ฒ„ํŒ€  |
+-------+----------------+
5 rows in set (0.00 sec)

Query OK, 0 rows affected (0.01 sec)

# WITH CTE

WITH - CTE

๋ฉ”๋ชจ๋ฆฌ์— ์ž„์‹œ ๊ฒฐ๊ณผ ์…‹์œผ๋กœ ์˜ฌ๋ ค๋†“๊ณ  ์žฌ์‚ฌ์šฉ. (cf. View, Function)

  • ์žฅ์ 
    ์ˆœ์„œ์— ์˜ํ•œ ์ ˆ์ฐจ์ ์œผ๋กœ ์ž‘์„ฑ -> ์ž‘์„ฑํ•˜๊ธฐ ์‰ฝ๊ณ  ์ฝ๊ธฐ ์‰ฝ๋‹ค.
WITH [RECURSIVE]
    cte_name [(colr_name [, col_name] ...)] AS (subquery)
    [, cte_name [(colr_name [, col_name] ...)] AS (subquery)]
select * from cte_name;

MY SQL์˜ CTE์—๋Š” ์•„๋ž˜์™€ ๊ฐ™์ด 2๊ฐ€์ง€ CTE๋ฅผ ์ œ๊ณตํ•˜๊ณ  ์žˆ๋‹ค.

1. Common Table Expressions (๊ธฐ๋ณธ CTE) - ์ˆœ์ฐจ์ ์œผ๋กœ ์ฟผ๋ฆฌ ์ž‘์„ฑ ๊ฐ€๋Šฅ
2. Recursive Common Table Expressions (์žฌ๊ท€ CTE) - ์Šค์Šค๋กœ ์ถ”๊ฐ€์ ์ธ Row๋ฅผ ์ƒ์„ฑํ•  ์ˆ˜ ์žˆ๋‹ค.

WITH
  AvgSal AS ( -- ํ‰๊ท  ๊ธ‰์—ฌ
    select d.dname, avg(e.salary) avgsal
    from Dept d inner join Emp e on d.id = e.dept
    group by d.id
  ),
  MaxAvgSal AS ( -- ์ตœ๊ณ 
    select * from AvgSal order by avgSal desc limit 1
  ),
  MinAvgSal AS ( -- ์ตœ์†Œ
    select * from AvgSal order by avgSal asc limit 1
  ),
  SumUp AS ( -- union
    select '์ตœ๊ณ ' as gb, m1.* from MaxAvgSal m1
    UNION
    select '์ตœ์ €' as gb, m2.* from MinAvgSal m2
  )
select * from Sumup
UNION
select '', 'ํ‰๊ท ๊ธ‰์—ฌ์ฐจ์•ก', format((max(avgsal) - min(avgsal))* 10000, 0) from SumUp;  -- ์ฐจ์•ก

+------+--------------+----------+
| gb   | dname        | avgsal   |
+------+--------------+----------+
| ์ตœ๊ณ  | ์„œ๋ฒ„ํŒ€       | 538.1818 |
| ์ตœ์ € | ์˜์—…3ํŒ€      | 450.0000 |
|      | ํ‰๊ท ๊ธ‰์—ฌ์ฐจ์•ก | 881,818  |
+------+--------------+----------+
3 rows in set (0.00 sec)

# ์žฌ๊ท€ CTE

# ํ”ผ๋ณด๋‚˜์น˜ ์ˆ˜์—ด

๋ณ€์ˆ˜์— ๋งž์ถฐ์„œ ์กฐํšŒํ•ด์•ผ ํ•œ๋‹ค.

WITH RECURSIVE fibonacci (n, fib_n, next_fib_n) AS -- ๋ณ€์ˆ˜ 3๊ฐœ
(
    select 1, 0, 1 -- 3๊ฐœ
    UNION ALL
    select n + 1, next_fib_n, fib_n + next_fib_n -- 3๊ฐœ
      from fibonacci where n < 10
)
select * from fibonacci;
+------+-------+------------+
| n    | fib_n | next_fib_n |
+------+-------+------------+
|    1 |     0 |          1 |
|    2 |     1 |          1 |
|    3 |     1 |          2 |
|    4 |     2 |          3 |
|    5 |     3 |          5 |
|    6 |     5 |          8 |
|    7 |     8 |         13 |
|    8 |    13 |         21 |
|    9 |    21 |         34 |
|   10 |    34 |         55 |
+------+-------+------------+
10 rows in set (0.00 sec)

# ๊ณ„์ธต ํ…Œ์ŠคํŠธ๋ฅผ ์œ„ํ•ด ๋ถ€์„œ๋ฅผ ๋„ฃ์–ด์ฃผ์ž

insert into Dept(pid, dname) values(6, '์ธํ”„๋ผ์…€');
insert into Dept(pid, dname) values(6, 'DB์…€');
insert into Dept(pid, dname) values(7, '๋ชจ๋ฐ”์ผ์…€');

# ์šฐ์„  ํŠธ๋ฆฌ๊ตฌ์กฐ๊ฐ€ ์•„๋‹Œ ํ˜•ํƒœ๋กœ ์กฐํšŒ

WITH RECURSIVE CteDept (id, pid, npname, dname, d) AS -- d: depth : ์‹คํ–‰์ˆœ์„œ
(
  select id, pid, cast('' as char(31)), dname, 0 from Dept where pid = 0
  UNION ALL
  select d.id, d.pid, cte.dname, d.dname,  d + 1 from Dept d inner join CteDept cte on d.pid = cte.id
)
select * from CteDept;

+------+------+--------+----------+------+
| id   | pid  | npname | dname    | d    |
+------+------+--------+----------+------+
|    1 |    0 |        | ์˜์—…๋ถ€   |    0 |
|    2 |    0 |        | ๊ฐœ๋ฐœ๋ถ€   |    0 |
|    3 |    1 | ์˜์—…๋ถ€ | ์˜์—…1ํŒ€  |    1 |
|    4 |    1 | ์˜์—…๋ถ€ | ์˜์—…2ํŒ€  |    1 |
|    5 |    1 | ์˜์—…๋ถ€ | ์˜์—…3ํŒ€  |    1 |
|    6 |    2 | ๊ฐœ๋ฐœ๋ถ€ | ์„œ๋ฒ„ํŒ€   |    1 |
|    7 |    2 | ๊ฐœ๋ฐœ๋ถ€ | ํด๋ผํŒ€   |    1 |
|    9 |    6 | ์„œ๋ฒ„ํŒ€ | ์ธํ”„๋ผ์…€ |    2 |
|   10 |    6 | ์„œ๋ฒ„ํŒ€ | DB์…€     |    2 |
|   11 |    7 | ํด๋ผํŒ€ | ๋ชจ๋ฐ”์ผ์…€ |    2 |
+------+------+--------+----------+------+
10 rows in set (0.00 sec)

# ํŠธ๋ฆฌ ๊ตฌ์กฐ๋กœ ์กฐํšŒ

WITH RECURSIVE CteDept (id, pid, npname, dname, d, h) AS 
(
  select id, pid, cast('' as char(31)), dname, 0, cast(id as char(10)) from Dept where pid = 0
  UNION ALL
  select d.id, d.pid, cte.dname, d.dname,  d + 1, concat(cte.h, '-', d.id) from Dept d inner join CteDept cte on d.pid = cte.id
)
select * from CteDept order by h;

+------+------+--------+----------+------+--------+
| id   | pid  | npname | dname    | d    | h      |
+------+------+--------+----------+------+--------+
|    1 |    0 |        | ์˜์—…๋ถ€   |    0 | 1      |
|    3 |    1 | ์˜์—…๋ถ€ | ์˜์—…1ํŒ€  |    1 | 1-3    |
|    4 |    1 | ์˜์—…๋ถ€ | ์˜์—…2ํŒ€  |    1 | 1-4    |
|    5 |    1 | ์˜์—…๋ถ€ | ์˜์—…3ํŒ€  |    1 | 1-5    |
|    2 |    0 |        | ๊ฐœ๋ฐœ๋ถ€   |    0 | 2      |
|    6 |    2 | ๊ฐœ๋ฐœ๋ถ€ | ์„œ๋ฒ„ํŒ€   |    1 | 2-6    |
|   10 |    6 | ์„œ๋ฒ„ํŒ€ | DB์…€     |    2 | 2-6-10 |
|    9 |    6 | ์„œ๋ฒ„ํŒ€ | ์ธํ”„๋ผ์…€ |    2 | 2-6-9  |
|    7 |    2 | ๊ฐœ๋ฐœ๋ถ€ | ํด๋ผํŒ€   |    1 | 2-7    |
|   11 |    7 | ํด๋ผํŒ€ | ๋ชจ๋ฐ”์ผ์…€ |    2 | 2-7-11 |
+------+------+--------+----------+------+--------+
10 rows in set (0.00 sec)

# ์žฌ๊ท€ ํšŸ์ˆ˜ ์ œํ•œํ•˜๊ธฐ

session์œผ๋กœ ํšŸ์ˆ˜ ์ œํ•œ

SET SESSION cte_max_recursion_depth = 20; -- ์žฌ๊ท€ ์‹คํ–‰ ์ œํ•œ
WITH RECURSIVE cte (n) AS
(
  SELECT 1
  UNION ALL
  SELECT n + 1 FROM cte -- limit 21 ๊นŒ์ง€ ๊ฐ€๋Šฅ
)
SELECT * FROM cte;

-- 20๋ฒˆ ์ด์ƒ ์‹คํ–‰๋˜๊ธฐ๋•Œ๋ฌธ์— ๋ฃจํ”„์— ๋น ์ง€์ง€ ์•Š๋„๋ก ์—๋Ÿฌ๊ฐ€ ๋ฐœ์ƒ๋œ๋‹ค. 

vuepress

์ฃผ์„ ํžŒํŠธ๋กœ ์ œํ•œ

SET SESSION cte_max_recursion_depth = 20; -- ์žฌ๊ท€ ์‹คํ–‰ ์ œํ•œ
WITH RECURSIVE cte (n) AS
(
  SELECT 1
  UNION ALL
  SELECT n + 1 FROM cte limit 21
)
SELECT /*+ SET_VAR(cte_max_recursion_depth = 10) */ * FROM cte; -- HINT! ์œ„์— session๋ณด๋‹ค ์šฐ์„ ..

-- 11๋ฒˆ ๊นŒ์ง€๋งŒ ๊ฐ€๋Šฅํ•˜๋‹ค๊ณ  ์—๋Ÿฌ๊ฐ€ ๋ฐœ์ƒ๋จ.

vuepress

# ์œˆ๋„์šฐ ํ•จ์ˆ˜

์ฐธ๊ณ  (opens new window)

# windowFunc() over(PARTITION BY ๊ทธ๋ฃน ORDER BY ์ •๋ ฌ๊ธฐ์ค€) ์ด๋ ‡๊ฒŒ ์‚ฌ์šฉํ•œ๋‹ค.

Window Function - 1

vuepress

ํ•จ์ˆ˜ ์„ค๋ช…
ROW_NUMBER() ์ „์ฒด ๊ฒฐ๊ณผ์—์„œ ํŒŒํ‹ฐ์…˜ ๊ธฐ์ค€ ์ถœ๋ ฅ๋˜๋Š” ํ–‰ ๋ฒˆํ˜ธ(์ˆœ๋ฒˆ)
RANK() ๊ฐ’์˜ ๋žญํ‚น(์ˆœ์œ„), ๊ณต๋™ ๋žญํ‚น์€ ๋™์ผ๊ฐ’์„ ๋ณด์ด๋ฉฐ ๋‹ค์Œ ๋žญํ‚น์€ ๊ณต๋™ ๋žญํ‚น์„ ๊ฑด๋„ˆ๋›ฐ์–ด ํ‘œ์‹œ
DESNE_RANK() RANK() ํ•จ์ˆ˜์™€ ๋™์ผํ•œ ๊ธฐ๋Šฅ์ด์ง€๋งŒ ๊ณต๋™ ๋žญํ‚น์„ ๊ฑด๋„ˆ๋›ฐ์ง€ ์•Š๋Š”๋‹ค.
PERCENT_RANK() ๋žญํ‚น์„ ๋ฐฑ๋ถ„์œจ๋กœ ๋‚˜ํƒ€๋‚ธ๋‹ค. ํŒŒํ‹ฐ์…˜ ๋‚ด์—์„œ ์œ„์น˜ํ•˜๋Š” ๋žญํ‚น์˜ %.
CUME_DIST() ํŒŒํ‹ฐ์…˜ ๋‚ด ์ฐจ์ง€ ํ•˜๋Š” ์œ„์น˜๋ฅผ ๋ˆ„์ (cumulative)๋œ ๊ฑฐ๋ฆฌ๋ฅผ %๋กœ ๋‚˜ํƒ€๋‚ด์–ด ๊ทธ๋ž˜ํ”„๋ฅผ ๊ทธ๋ฆฐ๋‹ค๋ฉด ๊ฒฝ๊ณ„(outbound)๋ฅผ ๋‚˜ํƒ€๋‚ธ๋‹ค.
NTILE(n) ํŒŒํ‹ฐ์…˜ ๋‚ด ๋กœ์šฐ๋“ค์„ n ๊ฐœ์˜ ๊ทธ๋ฃน์œผ๋กœ ๋‚˜๋ˆด์„ ๋•Œ ๊ทธ๋ฃน ๋ฒˆํ˜ธ. ๋ณดํ†ต ์ˆœ์„œ์— ๋งž์ถฐ ๊ทธ๋ฃน(์˜์—ญ)์„ ๋‚˜๋ˆŒ ๋•Œ ์‚ฌ์šฉ

Window Function - 2

vuepress

ํ•จ์ˆ˜ ์„ค๋ช…
FIRST_VALUE(col) ํŒŒํ‹ฐ์…˜ ๋‚ด ์ฒซ๋ฒˆ์งธ col ์ปฌ๋Ÿผ์˜ ๊ฐ’
LAST_VALUE(col) ํŒŒํ‹ฐ์…˜ ๋‚ด ๋งˆ์ง€๋ง‰ col ์ปฌ๋Ÿผ์˜ ๊ฐ’
NTH_VALUE(col, n) ํŒŒํ‹ฐ์…˜ ๋‚ด n๋ฒˆ์งธ col ์ปฌ๋Ÿผ์˜ ๊ฐ’
LAG(n) ํ˜„์žฌ ํ–‰ ๊ธฐ์ค€ ์•ž(์ด์ „) n ๋ฒˆ์งธ ๊ฐ’
LEAD(n) ํ˜„์žฌ ํ–‰ ๊ธฐ์ค€ ๋’ค(๋‹ค์Œ) n ๋ฒˆ์งธ ๊ฐ’
select row_number() over(order by dept, salary desc) '์ˆœ๋ฒˆ',
    e.*,
    rank() over w '๋ถ€์„œ๋‚ด ์ˆœ์œ„',
    dense_rank() over w '๋ถ€์„œ๋‚ด ์ˆœ์œ„',
    percent_rank() over w '๋ถ€์„œ๋‚ด %์ˆœ์œ„',
    cume_dist() over w '๋ถ€์„œ๋‚ด %๊ฒฝ๊ณ„',
    ntile(3) over w '๊ธ‰์—ฌ๋“ฑ๊ธ‰'
  from Emp e
where ename like '๋ฐ•%'
WINDOW w as (partition by dept order by dept, salary desc) -- ์ด๊ฑธ ์จ์ฃผ๋ฉด over()๋ฅผ ์จ์ฃผ์ง€ ์•Š์•„๋„ ๋œ๋‹ค.
;

 +------+-----+--------+------+--------+-------------+-------------+--------------------+---------------------+----------+
| ์ˆœ๋ฒˆ | id  | ename  | dept | salary | ๋ถ€์„œ๋‚ด ์ˆœ์œ„ | ๋ถ€์„œ๋‚ด ์ˆœ์œ„ | ๋ถ€์„œ๋‚ด %์ˆœ์œ„       | ๋ถ€์„œ๋‚ด %๊ฒฝ๊ณ„        | ๊ธ‰์—ฌ๋“ฑ๊ธ‰ |
+------+-----+--------+------+--------+-------------+-------------+--------------------+---------------------+----------+
|    1 | 169 | ๋ฐ•๊ตญ๊ฒฐ |    3 |    900 |           1 |           1 |                  0 |  0.3333333333333333 |        1 |
|    2 | 105 | ๋ฐ•ํ˜ธ๋งˆ |    3 |    700 |           2 |           2 |                0.5 |  0.6666666666666666 |        2 |
|    3 | 137 | ๋ฐ•์ˆœ๋‹ค |    3 |    400 |           3 |           3 |                  1 |                   1 |        3 |
|    4 | 147 | ๋ฐ•์„ธ์ฐจ |    4 |    900 |           1 |           1 |                  0 |                0.25 |        1 |
|    5 | 145 | ๋ฐ•๋ฏผ๋งˆ |    4 |    800 |           2 |           2 | 0.3333333333333333 |                 0.5 |        1 |
|    6 |  82 | ๋ฐ•์‚ฌ๊ฐ€ |    4 |    700 |           3 |           3 | 0.6666666666666666 |                   1 |        2 |
|    7 | 237 | ๋ฐ•๋ฏผ์‚ฌ |    4 |    700 |           3 |           3 | 0.6666666666666666 |                   1 |        3 |
|    8 | 143 | ๋ฐ•๋‹ค๋งˆ |    5 |    700 |           1 |           1 |                  0 |                 0.5 |        1 |
|    9 | 165 | ๋ฐ•์ˆœ๊ตญ |    5 |    300 |           2 |           2 |                  1 |                   1 |        2 |
|   10 |  43 | ๋ฐ•์•„๋‹ค |    6 |    900 |           1 |           1 |                  0 |  0.3333333333333333 |        1 |
|   11 |  44 | ๋ฐ•์ข…์ง€ |    6 |    900 |           1 |           1 |                  0 |  0.3333333333333333 |        1 |
|   12 |  71 | ๋ฐ•ํ˜ธ๋ฏผ |    6 |    800 |           3 |           2 |                0.4 |                 0.5 |        2 |
|   13 | 241 | ๋ฐ•๋งˆ์ฐฌ |    6 |    700 |           4 |           3 |                0.6 |  0.6666666666666666 |        2 |
|   14 |  93 | ๋ฐ•๋ฐ”ํ˜ธ |    6 |    300 |           5 |           4 |                0.8 |  0.8333333333333334 |        3 |
|   15 | 114 | ๋ฐ•๊ตญ์ˆœ |    6 |    100 |           6 |           5 |                  1 |                   1 |        3 |
|   16 |  49 | ๋ฐ•์‹ ๋‹ค |    7 |    900 |           1 |           1 |                  0 | 0.16666666666666666 |        1 |
|   17 | 223 | ๋ฐ•์ฐจ๊ฒฐ |    7 |    800 |           2 |           2 |                0.2 |  0.3333333333333333 |        1 |
|   18 |  47 | ๋ฐ•๋ฏผ์ž |    7 |    600 |           3 |           3 |                0.4 |                 0.5 |        2 |
|   19 |  37 | ๋ฐ•์ž๋งˆ |    7 |    500 |           4 |           4 |                0.6 |  0.6666666666666666 |        2 |
|   20 |  21 | ๋ฐ•๊ตญ์„ธ |    7 |    200 |           5 |           5 |                0.8 |                   1 |        3 |
|   21 | 238 | ๋ฐ•์ฐจ๊ฒฐ |    7 |    200 |           5 |           5 |                0.8 |                   1 |        3 |
+------+-----+--------+------+--------+-------------+-------------+--------------------+---------------------+----------+
21 rows in set (0.00 sec)
select row_number() over(order by dept, salary desc) '์ˆœ๋ฒˆ',
    e.*,
    sum(salary) over w '๊ธ‰์—ฌ ๋ˆ„์ ์น˜',
    first_value(salary) over w '๋ถ€์„œ๋‚ด 1๋“ฑ ๊ธ‰์—ฌ',
    last_value(salary) over w '๋ถ€์„œ๋‚ด ํ˜„์žฌ๊นŒ์ง€์˜ ๊ผด๋“ฑ ๊ธ‰์—ฌ',
    nth_value(salary, 2) over w '๋ถ€์„œ๋‚ด 2๋“ฑ ๊ธ‰์—ฌ',
    lag(salary, 1) over w '์ด์ „ ๊ธ‰์—ฌ',
    lead(salary, 1) over w '๋‹ค์Œ ๊ธ‰์—ฌ'
  from Emp e
where ename like '๋ฐ•%'
WINDOW w as (partition by dept order by dept, salary desc) -- ์ด๊ฑธ ์จ์ฃผ๋ฉด over()๋ฅผ ์จ์ฃผ์ง€ ์•Š์•„๋„ ๋œ๋‹ค.
;

+------+-----+--------+------+--------+-------------+-----------------+-----------------------------+-----------------+-----------+-----------+
| ์ˆœ๋ฒˆ | id  | ename  | dept | salary | ๊ธ‰์—ฌ ๋ˆ„์ ์น˜ | ๋ถ€์„œ๋‚ด 1๋“ฑ ๊ธ‰์—ฌ | ๋ถ€์„œ๋‚ด ํ˜„์žฌ๊นŒ์ง€์˜ ๊ผด๋“ฑ ๊ธ‰์—ฌ | ๋ถ€์„œ๋‚ด 2๋“ฑ ๊ธ‰์—ฌ | ์ด์ „ ๊ธ‰์—ฌ | ๋‹ค์Œ ๊ธ‰์—ฌ |
+------+-----+--------+------+--------+-------------+-----------------+-----------------------------+-----------------+-----------+-----------+
|    1 | 169 | ๋ฐ•๊ตญ๊ฒฐ |    3 |    900 |         900 |             900 |                         900 |            NULL |      NULL |       700 |
|    2 | 105 | ๋ฐ•ํ˜ธ๋งˆ |    3 |    700 |        1600 |             900 |                         700 |             700 |       900 |       400 |
|    3 | 137 | ๋ฐ•์ˆœ๋‹ค |    3 |    400 |        2000 |             900 |                         400 |             700 |       700 |      NULL |
|    4 | 147 | ๋ฐ•์„ธ์ฐจ |    4 |    900 |         900 |             900 |                         900 |            NULL |      NULL |       800 |
|    5 | 145 | ๋ฐ•๋ฏผ๋งˆ |    4 |    800 |        1700 |             900 |                         800 |             800 |       900 |       700 |
|    6 |  82 | ๋ฐ•์‚ฌ๊ฐ€ |    4 |    700 |        3100 |             900 |                         700 |             800 |       800 |       700 |
|    7 | 237 | ๋ฐ•๋ฏผ์‚ฌ |    4 |    700 |        3100 |             900 |                         700 |             800 |       700 |      NULL |
|    8 | 143 | ๋ฐ•๋‹ค๋งˆ |    5 |    700 |         700 |             700 |                         700 |            NULL |      NULL |       300 |
|    9 | 165 | ๋ฐ•์ˆœ๊ตญ |    5 |    300 |        1000 |             700 |                         300 |             300 |       700 |      NULL |
|   10 |  43 | ๋ฐ•์•„๋‹ค |    6 |    900 |        1800 |             900 |                         900 |             900 |      NULL |       900 |
|   11 |  44 | ๋ฐ•์ข…์ง€ |    6 |    900 |        1800 |             900 |                         900 |             900 |       900 |       800 |
|   12 |  71 | ๋ฐ•ํ˜ธ๋ฏผ |    6 |    800 |        2600 |             900 |                         800 |             900 |       900 |       700 |
|   13 | 241 | ๋ฐ•๋งˆ์ฐฌ |    6 |    700 |        3300 |             900 |                         700 |             900 |       800 |       300 |
|   14 |  93 | ๋ฐ•๋ฐ”ํ˜ธ |    6 |    300 |        3600 |             900 |                         300 |             900 |       700 |       100 |
|   15 | 114 | ๋ฐ•๊ตญ์ˆœ |    6 |    100 |        3700 |             900 |                         100 |             900 |       300 |      NULL |
|   16 |  49 | ๋ฐ•์‹ ๋‹ค |    7 |    900 |         900 |             900 |                         900 |            NULL |      NULL |       800 |
|   17 | 223 | ๋ฐ•์ฐจ๊ฒฐ |    7 |    800 |        1700 |             900 |                         800 |             800 |       900 |       600 |
|   18 |  47 | ๋ฐ•๋ฏผ์ž |    7 |    600 |        2300 |             900 |                         600 |             800 |       800 |       500 |
|   19 |  37 | ๋ฐ•์ž๋งˆ |    7 |    500 |        2800 |             900 |                         500 |             800 |       600 |       200 |
|   20 |  21 | ๋ฐ•๊ตญ์„ธ |    7 |    200 |        3200 |             900 |                         200 |             800 |       500 |       200 |
|   21 | 238 | ๋ฐ•์ฐจ๊ฒฐ |    7 |    200 |        3200 |             900 |                         200 |             800 |       200 |      NULL |
+------+-----+--------+------+--------+-------------+-----------------+-----------------------------+-----------------+-----------+-----------+
21 rows in set (0.00 sec)

# JSON ๋ฐ์ดํ„ฐ ๋‹ค๋ฃจ๊ธฐ

JSON ํ•จ์ˆ˜ ์„ค๋ช…
JSON_VALID() ๋ฐ์ดํ„ฐ์˜ ์œ ํšจ์„ฑ ๊ฒ€์‚ฌ
JSON_PRETTY() ๋“ค์—ฌ์“ฐ๊ธฐ๋ฅผ ํฌํ•จํ•ด ๋ณด๊ธฐ ์ข‹๊ฒŒ JSON ๋ฐ์ดํ„ฐ ์ถœ๋ ฅ
JSON_OBJECT() ๋ฌธ์ž์—ด ํ˜•ํƒœ๊ฐ€ ์•„๋‹Œ key, value ์Œ์œผ๋กœ JSON ๋ฐ์ดํ„ฐ ๋งŒ๋“ค๊ธฐ
JSON_ARRAY() JSON ๋ฐ์ดํ„ฐ๋ฅผ ๋ฐฐ์—ด(Array) ํ˜•ํƒœ๋กœ ์ž‘์„ฑ ๋ฐ ๋ณ€ํ™˜
JSON_EXTRACT() ์ธ๋ผ์ธ ํŒจ์Šค(->)์™€ ๊ฐ™์ด ํŠน์ • ๊ฐ’๋งŒ ๋ฝ‘์•„ ์ถ”์ถœ
JSON_VALUE() ํŠน์ • ๊ฐ’ ์ถ”์ถœ, ์ถœ๋ ฅ ํƒ€์ž… ์ •์˜ ๊ฐ€๋Šฅ
JSON_QUOTE() ํŠน์ • ๊ฐ’ ์ถ”์ถœ์‹œ ๊ฐ’์˜ ์ขŒ์šฐ์— ํฐ๋”ฐ์˜ดํ‘œ ๋ถ™์—ฌ์„œ ์ถœ๋ ฅ
JSON_UNQUOTE() ํŠน์ • ๊ฐ’ ์ถ”์ถœ์‹œ ๊ฐ’์˜ ์ขŒ์šฐ์— ์ถœ๋ ฅ๋˜๋Š” ํฐ๋”ฐ์˜ดํ‘œ ์ œ๊ฑฐ
JSON_LENGTH() JSON ๋ฐ์ดํ„ฐ์˜ ํ‚ค ๊ฐœ์ˆ˜
JSON_DEPTH() JSON ๋ฐ์ดํ„ฐ์˜ ๊นŠ์ด(๊ณ„์ธต)
JSON_KEYS() JSON ๋ฐ์ดํ„ฐ์˜ key๋“ค๋งŒ ์ถ”์ถœ
JSON_TYPE() JSON ๋ฐ์ดํ„ฐ์˜ ๋ฐ์ดํ„ฐ ํƒ€์ž… ์ถœ๋ ฅ
JSON_SEARCH() ํŠน์ •๊ฐ’์œผ๋กœ JSON ํŒจ์Šค(์œ„์น˜) ๊ฒ€์ƒ‰
JSON_CONTAINS() JSON ๋ฐ์ดํ„ฐ์— ํŠน์ • ๊ฐ’์˜ ์กด์žฌ ์—ฌ๋ถ€ ํ™•์ธ
JSON_REPLACE() JSON ๋ฐ์ดํ„ฐ์˜ ๊ฐ’ ๋ถ€๋ถ„ ๋ณ€๊ฒฝ
JSON_INSERT() JSON ๋ฐ์ดํ„ฐ์— ํŠน์ • key, value ์Œ์„ ์ถ”๊ฐ€
JSON_SET() JSON ๋ฐ์ดํ„ฐ์—์„œ ํŠน์ • key์— ํ•ด๋‹น๋˜๋Š” ๊ฐ’๋งŒ ๋ณ€๊ฒฝ
JSON_REMOVE() JSON ๋ฐ์ดํ„ฐ์˜ ํŠน์ • key, value ์ œ๊ฑฐ
JSON_MERGE() ๊ธฐ์กด JSON ๋ฐ์ดํ„ฐ์— ๊ฐ’ ์ถ”๊ฐ€, MySQL 8์—์„œ deprecated๋จ
JSON_MERGE_PRESERVE() JSON ๋ฐ์ดํ„ฐ ํŠน์ • ์œ„์น˜์˜ ๊ฐ’ ๋ณ€๊ฒฝ(๊ธฐ์กด ๊ฐ’ ์œ ์ง€)
JSON_MERGE_PATCH() JSON ๋ฐ์ดํ„ฐ ํŠน์ • ์œ„์น˜์˜ ๊ฐ’ ๋ณ€๊ฒฝ(๊ธฐ์กด ๊ฐ’ ๋Œ€์น˜)
JSON_TABLE() JSON ๋ฐ์ดํ„ฐ๋ฅผ ํ…Œ์ด๋ธ” ํ˜•ํƒœ๋กœ ์ •์˜
JSON_ARRAYAGG() ์ „์ฒด JSON ๋ฐ์ดํ„ฐ๋ฅผ ์ทจํ•ฉ(ํ†ตํ•ฉ)ํ•˜์—ฌ ๋ฐฐ์—ด๋กœ ์ถœ๋ ฅ
JSON_OBJECTAGG() JSON ๋ฐ์ดํ„ฐ๋ฅผ ์ทจํ•ฉ(ํ†ตํ•ฉ)ํ•˜์—ฌ Object ํ˜•ํƒœ๋กœ ์ถœ๋ ฅ
JSON_STORAGE_SIZE() JSON ๋ฐ์ดํ„ฐ๊ฐ€ ์ฐจ์ง€ํ•˜๋Š” ๋ฐ์ดํ„ฐ ํฌ๊ธฐ
JSON_STORAGE_FREE() JSON ๋ฐ์ดํ„ฐ ์ปฌ๋Ÿผ์˜ ์—ฌ์œ ๊ณต๊ฐ„, JSON ๋ฐ์ดํ„ฐ ์žˆ์œผ๋ฉด ํ•ญ์ƒ 0
alter table Emp add column remark JSON;

desc Emp;

update Emp set remark = '{ "addr": "์„œ์šธ"}'
  where id = 1;
  
update Emp set remark = '{"addr": "๋ถ€์‚ฐ", "age": 39}'
 where id = 2;
 
update Emp set remark = '{"addr": "๋Œ€๊ตฌ", "age": 29, "family": [ {"name": "๋…ผ๊ฐœ", "relation": "๋ชจ"} ]}'
 where id = 3;
 
update Emp set remark = '{"addr": "๊ฐ•์›", "age": 49, "family": [  {"name": "์กฐ์กฐ", "relation": "๋ถ€"},  {"name": "๋ฐฐ์ฒ ๊ท ", "relation": "๋ชจ"} ]}'
 where id = 4;
 
update Emp set remark = '{"addr": "์„œ์šธ", "addr": "๋Œ€์ „"}'
 where id = 1;  
 
update Emp set remark = json_object('addr', "๋ถ€์‚ฐ", "age", 38)
 where id = 2;

update Emp set remark = json_object('addr', "๋Œ€๊ตฌ", "age", 28, 
          "family", json_array(
              json_object('name', '๋…ผ๊ฐœ', 'relation', '๋ชจ')
          )) 
where id = 3;

--  {
--    "age": 48,
--    "addr": "๊ฐ•์›",
--    "family": [
--      {
--        "name": "์กฐ์กฐ",
--        "relation": "๋ถ€"
--      },
--      {
--        "name": "๋ฐฐ์ฒ ๊ท ",
--        "relation": "๋ชจ"
--      }
--    ]
--  }
update Emp set remark = json_object('addr', "๊ฐ•์›", "age", 48, 
          "family", json_array(
              json_object("name", "์กฐ์กฐ", "relation", "๋ถ€"), 
              json_object("name", "๋ฐฐ์ฒ ๊ท ", "relation", "๋ชจ")
          ))
where id = 4;

JSON ๊ฐ’ ์ถ”์ถœ

select remark,
  remark->'$.addr', -- $๋Š” ๋ฃจํŠธ
  remark->>'$.addr', -- >> ๊บฝ์ƒˆ๊ฐ€ ๋‘๊ฐœ๋ฉด ์Œ๋”ฐ์˜ดํ‘œ๊ฐ€ ์—†์–ด์ง„๋‹ค.
  json_value(remark, '$.addr'),
  json_value(remark, '$.age' returning decimal(4,2)),
  -- remark ๋‚˜์˜ค๊ธฐ ์ „..
  json_extract(remark, '$.addr'),
  json_unquote(json_extract(remark, '$.addr'))
from Emp
where remark is not null;

+-------------------------------------------------------------------------------------------------------------------+------------------+-------------------+------------------------------+----------------------------------------------------+--------------------------------+----------------------------------------------+
| remark                                                                                                            | remark->'$.addr' | remark->>'$.addr' | json_value(remark, '$.addr') | json_value(remark, '$.age' returning decimal(4,2)) | json_extract(remark, '$.addr') | json_unquote(json_extract(remark, '$.addr')) |
+-------------------------------------------------------------------------------------------------------------------+------------------+-------------------+------------------------------+----------------------------------------------------+--------------------------------+----------------------------------------------+
| {"addr": "๋Œ€์ „"}                                                                                                  | "๋Œ€์ „"           | ๋Œ€์ „              | ๋Œ€์ „                         |                                               NULL | "๋Œ€์ „"                         | ๋Œ€์ „                                         |
| {"age": 38, "addr": "๋ถ€์‚ฐ"}                                                                                       | "๋ถ€์‚ฐ"           | ๋ถ€์‚ฐ              | ๋ถ€์‚ฐ                         |                                              38.00 | "๋ถ€์‚ฐ"                         | ๋ถ€์‚ฐ                                         |
| {"age": 28, "addr": "๋Œ€๊ตฌ", "family": [{"name": "๋…ผ๊ฐœ", "relation": "๋ชจ"}]}                                       | "๋Œ€๊ตฌ"           | ๋Œ€๊ตฌ              | ๋Œ€๊ตฌ                         |                                              28.00 | "๋Œ€๊ตฌ"                         | ๋Œ€๊ตฌ                                         |
| {"age": 48, "addr": "๊ฐ•์›", "family": [{"name": "์กฐ์กฐ", "relation": "๋ถ€"}, {"name": "๋ฐฐ์ฒ ๊ท ", "relation": "๋ชจ"}]} | "๊ฐ•์›"           | ๊ฐ•์›              | ๊ฐ•์›                         |                                              48.00 | "๊ฐ•์›"                         | ๊ฐ•์›                                         |
+-------------------------------------------------------------------------------------------------------------------+------------------+-------------------+------------------------------+----------------------------------------------------+--------------------------------+----------------------------------------------+
4 rows in set (0.00 sec)

JSON ๊ฒ€์ƒ‰

select remark,
  json_search(remark, 'one', '๋ถ€์‚ฐ'), -- ๊ฒฐ๊ณผ๋กœ path๋ฅผ ์•Œ๋ ค์ค€๋‹ค.
  json_search(remark, 'one', '๋ฐฐ์ฒ ๊ท '),
  json_value(remark, "$.family[0].name")
from Emp
where remark is not null;

+-------------------------------------------------------------------------------------------------------------------+------------------------------------+--------------------------------------+----------------------------------------+
| remark                                                                                                            | json_search(remark, 'one', '๋ถ€์‚ฐ') | json_search(remark, 'one', '๋ฐฐ์ฒ ๊ท ') | json_value(remark, "$.family[0].name") |
+-------------------------------------------------------------------------------------------------------------------+------------------------------------+--------------------------------------+----------------------------------------+
| {"addr": "๋Œ€์ „"}                                                                                                  | NULL                               | NULL                                 | NULL                                   |
| {"age": 38, "addr": "๋ถ€์‚ฐ"}                                                                                       | "$.addr"                           | NULL                                 | NULL                                   |
| {"age": 28, "addr": "๋Œ€๊ตฌ", "family": [{"name": "๋…ผ๊ฐœ", "relation": "๋ชจ"}]}                                       | NULL                               | NULL                                 | ๋…ผ๊ฐœ                                   |
| {"age": 48, "addr": "๊ฐ•์›", "family": [{"name": "์กฐ์กฐ", "relation": "๋ถ€"}, {"name": "๋ฐฐ์ฒ ๊ท ", "relation": "๋ชจ"}]} | NULL                               | "$.family[1].name"                   | ์กฐ์กฐ                                   |
+-------------------------------------------------------------------------------------------------------------------+------------------------------------+--------------------------------------+----------------------------------------+
4 rows in set (0.00 sec)

JSON ๊ฒ€์ƒ‰ 2

select remark,
    json_contains(remark, '"๋ถ€์‚ฐ"', '$.addr'),
    json_contains(remark, '48', '$.age')
from Emp
where remark is not null;

+-------------------------------------------------------------------------------------------------------------------+-------------------------------------------+--------------------------------------+
| remark                                                                                                            | json_contains(remark, '"๋ถ€์‚ฐ"', '$.addr') | json_contains(remark, '48', '$.age') |
+-------------------------------------------------------------------------------------------------------------------+-------------------------------------------+--------------------------------------+
| {"addr": "๋Œ€์ „"}                                                                                                  |                                         0 |                                 NULL |
| {"age": 38, "addr": "๋ถ€์‚ฐ"}                                                                                       |                                         1 |                                    0 |
| {"age": 28, "addr": "๋Œ€๊ตฌ", "family": [{"name": "๋…ผ๊ฐœ", "relation": "๋ชจ"}]}                                       |                                         0 |                                    0 |
| {"age": 48, "addr": "๊ฐ•์›", "family": [{"name": "์กฐ์กฐ", "relation": "๋ถ€"}, {"name": "๋ฐฐ์ฒ ๊ท ", "relation": "๋ชจ"}]} |                                         0 |                                    1 |
+-------------------------------------------------------------------------------------------------------------------+-------------------------------------------+--------------------------------------+
4 rows in set (0.01 sec)

select * from Emp where json_contains(remark, '48', '$.age');
+----+--------+------+--------+-------------------------------------------------------------------------------------------------------------------+
| id | ename  | dept | salary | remark                                                                                                            |
+----+--------+------+--------+-------------------------------------------------------------------------------------------------------------------+
|  4 | ์ตœํ˜ธ์ˆœ |    5 |    400 | {"age": 48, "addr": "๊ฐ•์›", "family": [{"name": "์กฐ์กฐ", "relation": "๋ถ€"}, {"name": "๋ฐฐ์ฒ ๊ท ", "relation": "๋ชจ"}]} |
+----+--------+------+--------+-------------------------------------------------------------------------------------------------------------------+
1 row in set (0.00 sec)

select * from Emp where json_value(remark, '$.age') = 48;
+----+--------+------+--------+-------------------------------------------------------------------------------------------------------------------+
| id | ename  | dept | salary | remark                                                                                                            |
+----+--------+------+--------+-------------------------------------------------------------------------------------------------------------------+
|  4 | ์ตœํ˜ธ์ˆœ |    5 |    400 | {"age": 48, "addr": "๊ฐ•์›", "family": [{"name": "์กฐ์กฐ", "relation": "๋ถ€"}, {"name": "๋ฐฐ์ฒ ๊ท ", "relation": "๋ชจ"}]} |
+----+--------+------+--------+-------------------------------------------------------------------------------------------------------------------+
1 row in set (0.00 sec)

select * from Emp where remark->>'$.age' = 48;
+----+--------+------+--------+-------------------------------------------------------------------------------------------------------------------+
| id | ename  | dept | salary | remark                                                                                                            |
+----+--------+------+--------+-------------------------------------------------------------------------------------------------------------------+
|  4 | ์ตœํ˜ธ์ˆœ |    5 |    400 | {"age": 48, "addr": "๊ฐ•์›", "family": [{"name": "์กฐ์กฐ", "relation": "๋ถ€"}, {"name": "๋ฐฐ์ฒ ๊ท ", "relation": "๋ชจ"}]} |
+----+--------+------+--------+-------------------------------------------------------------------------------------------------------------------+
1 row in set (0.00 sec)

# rollup

select 
  (case when d.pid is not null then max(p.dname) else 'Total' end) '์ƒ์œ„๋ถ€์„œ',
  (case when d.id is not null then max(d.dname) else '- ์†Œ๊ณ„ -' end) '๋ถ€์„œ๋ช…', 
  format(sum(e.salary), 0) '๊ธ‰์—ฌํ•ฉ(๋‹จ์œ„:๋งŒ์›)'
from Dept p inner join Dept d on p.id = d.pid
            inner join Emp e on d.id = e.dept
group by d.pid, d.id
with rollup;
+----------+----------+-------------------+
| ์ƒ์œ„๋ถ€์„œ | ๋ถ€์„œ๋ช…   | ๊ธ‰์—ฌํ•ฉ(๋‹จ์œ„:๋งŒ์›) |
+----------+----------+-------------------+
| ์˜์—…๋ถ€   | ์˜์—…1ํŒ€  | 28,600            |
| ์˜์—…๋ถ€   | ์˜์—…2ํŒ€  | 24,900            |
| ์˜์—…๋ถ€   | ์˜์—…3ํŒ€  | 20,700            |
| ์˜์—…๋ถ€   | - ์†Œ๊ณ„ - | 74,200            |
| ๊ฐœ๋ฐœ๋ถ€   | ์„œ๋ฒ„ํŒ€   | 29,600            |
| ๊ฐœ๋ฐœ๋ถ€   | ํด๋ผํŒ€   | 23,700            |
| ๊ฐœ๋ฐœ๋ถ€   | - ์†Œ๊ณ„ - | 53,300            |
| Total    | - ์†Œ๊ณ„ - | 127,500           |
+----------+----------+-------------------+
8 rows in set (0.00 sec)

# pivot

select d.id, max(d.dname) '๊ตฌ๋ถ„',
  format(avg(e.salary) * 10000, 0) 'ํ‰๊ท ๊ธ‰์—ฌ',
  format(sum(e.salary) * 10000, 0) '๊ธ‰์—ฌํ•ฉ๊ณ„',
  format(min(e.salary) * 10000, 0) '์ตœ์†Œ๊ธ‰์—ฌ',
  format(max(e.salary) * 10000, 0) '์ตœ๋Œ€๊ธ‰์—ฌ'
from Dept d inner join Emp e on d.id = e.dept
group by d.id
order by d.id;
+----+---------+-----------+-------------+-----------+-----------+
| id | ๊ตฌ๋ถ„    | ํ‰๊ท ๊ธ‰์—ฌ  | ๊ธ‰์—ฌํ•ฉ๊ณ„    | ์ตœ์†Œ๊ธ‰์—ฌ  | ์ตœ๋Œ€๊ธ‰์—ฌ  |
+----+---------+-----------+-------------+-----------+-----------+
|  3 | ์˜์—…1ํŒ€ | 4,612,903 | 286,000,000 | 1,000,000 | 9,000,000 |
|  4 | ์˜์—…2ํŒ€ | 5,297,872 | 249,000,000 | 1,000,000 | 9,000,000 |
|  5 | ์˜์—…3ํŒ€ | 4,500,000 | 207,000,000 | 1,000,000 | 9,000,000 |
|  6 | ์„œ๋ฒ„ํŒ€  | 5,381,818 | 296,000,000 | 1,000,000 | 9,000,000 |
|  7 | ํด๋ผํŒ€  | 4,647,059 | 237,000,000 | 1,000,000 | 9,000,000 |
+----+---------+-----------+-------------+-----------+-----------+
5 rows in set (0.00 sec)
select 'ํ‰๊ท ๊ธ‰์—ฌ' as '๊ตฌ๋ถ„',
  format(avg(case when dept = 3 then salary end) * 10000, 0) '์˜์—…1ํŒ€',
  format(avg(case when dept = 4 then salary end) * 10000, 0) '์˜์—…2ํŒ€',
  format(avg(case when dept = 5 then salary end) * 10000, 0) '์˜์—…3ํŒ€',
  format(avg(case when dept = 6 then salary end) * 10000, 0) '์„œ๋ฒ„ํŒ€',
  format(avg(case when dept = 7 then salary end) * 10000, 0) 'ํด๋ผํŒ€'
from Emp
UNION
select '๊ธ‰์—ฌํ•ฉ๊ณ„',
  format(sum(salary * (dept = 3)) * 10000, 0), -- ๋ถ€์„œ๊ฐ€ 3์ด๋ฉด 1์ด๋‹ˆ๊นŒ.. ๋ถ€์„œ๊ฐ€ 3์ธ ์ง์›์˜ salary๋งŒ ๊ฐ€์ ธ์˜จ๋‹ค
  format(sum(salary * (dept = 4)) * 10000, 0), 
  format(sum(salary * (dept = 5)) * 10000, 0), 
  format(sum(salary * (dept = 6)) * 10000, 0), 
  format(sum(salary * (dept = 7)) * 10000, 0)
from Emp
UNION
select '์ตœ์†Œ๊ธ‰์—ฌ',    
  format(min(IF(dept = 3, salary, ~0)) * 10000, 0), -- ~0: integer์˜ ์ตœ๋Œ“๊ฐ’
  format(min(IF(dept = 4, salary, ~0)) * 10000, 0),
  format(min(IF(dept = 5, salary, ~0)) * 10000, 0),
  format(min(IF(dept = 6, salary, ~0)) * 10000, 0),
  format(min(IF(dept = 7, salary, ~0)) * 10000, 0)
from Emp
UNION
select '์ตœ๋Œ€๊ธ‰์—ฌ',    
  format(max(IF(dept = 3, salary, 0)) * 10000, 0),
  format(max(IF(dept = 4, salary, 0)) * 10000, 0),
  format(max(IF(dept = 5, salary, 0)) * 10000, 0),
  format(max(IF(dept = 6, salary, 0)) * 10000, 0),
  format(max(IF(dept = 7, salary, 0)) * 10000, 0)
from Emp
;
+----------+-------------+-------------+-------------+-------------+-------------+
| ๊ตฌ๋ถ„     | ์˜์—…1ํŒ€     | ์˜์—…2ํŒ€     | ์˜์—…3ํŒ€     | ์„œ๋ฒ„ํŒ€      | ํด๋ผํŒ€      |
+----------+-------------+-------------+-------------+-------------+-------------+
| ํ‰๊ท ๊ธ‰์—ฌ | 4,612,903   | 5,297,872   | 4,500,000   | 5,381,818   | 4,647,059   |
| ๊ธ‰์—ฌํ•ฉ๊ณ„ | 286,000,000 | 249,000,000 | 207,000,000 | 296,000,000 | 237,000,000 |
| ์ตœ์†Œ๊ธ‰์—ฌ | 1,000,000   | 1,000,000   | 1,000,000   | 1,000,000   | 1,000,000   |
| ์ตœ๋Œ€๊ธ‰์—ฌ | 9,000,000   | 9,000,000   | 9,000,000   | 9,000,000   | 9,000,000   |
+----------+-------------+-------------+-------------+-------------+-------------+
4 rows in set (0.00 sec)

# Reference

inflearn_@์‹œ์ฝ” - MySQL ์ œ๋Œ€๋กœ ๋ฐฐ์šฐ๊ธฐ (opens new window)
๊ฐ•์˜ github (opens new window)
๊ฐ•์˜ slide (opens new window)
mysql ์‚ฌ์šฉ์ž (opens new window)

Last Updated: 3/8/2024, 5:46:31 AM