비트교육센터/MySql

[비트교육센터] MySql 20일차 Select

달의요정루나 2023. 6. 28. 09:06

1. Select

- Selection: 테이블에서 전체 칼럼을 출력시켜주면 Selection이다.

- Projection: 테이블에서 일부 칼럼을 출력시켜주면 Projection이다.

- Join: 서로 다른 테이블을 연결해 한번에 데이터를 함께 검색할 수 있음.

 

1) 테이블 조회하기

[1] 이용할 데이터베이스를 선택한다.

use scottdb;

[2] 현존하는 테이블에 대한 정보를 보여준다.

show tables;

[3] 해당 테이블에 대한 정보를 보여준다.

desc emp;

- char: 고정형 문자열이다. 공간이 낭비될 수 있지만 검색 속도가 varchar에 비해 빠르다.
   ex) char(10): 10바이트 공간을 차지한다. 문자가 몇개가 들어오든 10바이트를 유지한다.

- varchar(variable character): 가변형 문자열로 메모리의 길이에 따라 가변적으로 길이를 정한다. 메모리 사용량을 줄일 수 있다.
   ex) varchar(10): 10글자 쓸수 있는데 7만큼 쓰면 7칸만 메모리를 사용한다.

- datetime: 날짜 시간을 나타내주는 타입이다.
- Primary Key: 각 행의 데이터를 구별할 수 있도록 해준다. NOT NULL과 UNIQUE 제약 조건의 특징을 가진다.

- int: 숫자데이터로 정수형 데이터이다.

- double: 숫자데이터로 소수점 아래 15자리까지 표현이 가능하다.

 

2) emp 테이블 전체 출력하기(Selection)

[1]

select * from emp;

- 칼럼 전체가 출력되었다.(Selection)

 

3) 칼럼 일부 출력하기(Projection)

[1]

select empno from emp;

- emp 테이블에서 empno 칼럼에 있는 값을 전체출력한다.

[2]

select empno, job from emp;

- emp 테이블에서 empno칼럼, job칼럼에 있는 값 전체를 출력한다.

[3]

select empno 이름, job 담당업무 from emp;
-- 혹은
select empno as 이름, job as 담당업무 from emp;

- emp 테이블에서 empno칼럼, job칼럼에 있는 값 전체를 출력하면서 해당 칼럼의 별칭(alias)을 정해준다.

 

4) 개수 세기

[1]

select count(*) from emp;

- 전체 행 개수를 가지고 온다.

[2]

select count(comm) from emp;

- 해당 컬럼의 데이터 개수를 가지고 온다.

 

5) limit

[1]

select * from emp limit 5;

- select * from 테이블 이름 으로 전체를 출력할때 만약 데이터 개수가 1000만건이나 된다면 delay가 걸릴 수 있다.

- 데이터가 많을 경우 limit을 걸어서 데이터를 제한할 필요가 있다.

 

6) distinct

[1] distinct를 안썼을때

select job from emp;

[2] distinct를 썼을때

select distinct job from emp;

- distinct를 쓰면 중복된 값을 제거할 수 있다.

 

select count(distinct job) from emp;

--> 결과

5

distince를 선언하고 count를 써서 업무 갯수를 출력할 수 있다.

 

7) 칼럼 연산

[1]

select ename, sal*12 from emp;

- 해당 칼럼에 있는 값들에 12를 곱해서 출력한다.

[2]

select sal, comm, (sal+comm)*12 from emp;

- sal 칼럼과 comm 칼럼에 있는 값을 더해준후 12를 곱해 출력한다.

- 단, null이 들어갔을 경우 어떤 연산을 하든 무조건 null로 출력한다.

[3]

select sal, comm, (sal+ifnull(comm, 0))*12 from emp;

- ifnull을 선언해 comm 칼럼에 있는 값들 중 null일시 0으로 처리하게 한다.

 

8) 조건 입력(WHERE)

WHERE: 조회하는 결과에 특정한 조건을 줘서 원하는 데이터만 보고 싶을 때 사용한다.

SELECT 필드이름 FROM 테이블 이름 WHERE 조건식;

[1]

select ename, job, sal
from emp
where sal >= 1200;

- where를 선언해 한달 원급이 1200달러 이상인 ename, job, sal 컬럼의 값들을 출력시킨다.

[2]

select ename, job, hiredate
from emp
where job = 'CLERK';

- job 칼럼에 CLERK 값이 있는 행을 출력한다.

- 여담으로 SQL Server에서는 CLERK를 clerk로 입력해도 가능하다. 단, ORACLE에서는 대소문자를 철저히 구별한다.

[3]

select ename, job, hiredate
from emp
where job != 'CLERK';

- [2]하고 반대의 코드이다. 이번에는 CLERK 값이 없는 행을 출력시킨다.

[4]

select ename, job, hiredate
from emp
where hiredate = '1980-12-17';

- hiredate 칼럼에 1980-12-17 때의 열을 출력한다.

[5] like

select *
from emp
where ename like 'S%';

- ename칼럼에서 S로 시작하는 모든 것들을 출력한다.

- like는 특정문자가 포함되어 있는지 검색하는 역할을 한다.

[6]

select *
from emp
where comm is null;

- comm 칼럼에 NULL있는 데이터를 전부 출력한다.

- ==null이 아닌 is null로 선언해야 한다.

[7]

select *
from emp
where comm is not null;

- [6]번 문항의 반드이다. 이번에는 NULL이 없는 데이터들을 출력한다.

[8]

select ENAME, JOB, SAL
from emp
where not(SAL>=2000);

- SAL 칼럼에서 2000이상의 값을 부정한다.

- MySQL에서 NOT은 조건을 부정한다.

[9]

select ENAME, JOB, SAL
from EMP
where ename like '_A%';

- _다음에 A가 있다. 즉, 2번째 문자열이 무조건 A인 단어를 출력한다. %는 뒤에 무엇이 오든 상관없다.

[10]

select ENAME, JOB, SAL
from EMP
where ename like '%H';

- 가장 뒤에 H가 오는 문자를 조회한다. 앞에는 상관없다.

 

9) 2가지 조건 동시 입력(WHERE)

[1]

select ename, job
from emp
where job = 'CLERK' or job = 'SALESMAN';

- job 칼럼에 CLERK 혹은 SALESMAN 값이 있는 행을 출력한다.

[2] IN

select ename, job
from emp
where job in('CLERK', 'SALESMAN');

- IN: 여러 값을 OR 관계로 묶어 나열하는 조건을 WHERE 절에 사용할 때 쓴다.

[3]

select ename, job, hiredate
from emp
where hiredate >= '1980-12-01' and hiredate < '1981-06-01';

- hiredate 칼럼에서 1980-12-01부터 1981-06-01 전까지의 데이터를 출력한다.

[4]

select ename, job, hiredate
from emp
where hiredate between '1980-12-01' and '1981-06-01';

- [3]번 코드를 between을 통해서 작성한다. 양식은 between A and B이다. A와 B에 값을 넣어 범위를 정해줄 수 있다.

[5]

select ENAME, JOB, SAL
from emp
where SAL>=2000 and HIREDATE < '1981-06-01';

- sal이 2000이상이고 입사일이 1981년 6월 이전에 입사한 직원의 이름과 업무, 급여를 출력한다.

 

10) ORDER BY

ORDER BY: 결과가 출력되는 순서를 조절하는 구문이다.

[1]

select empno, ename, job
from emp
order by ename;

- ename 칼럼 기준으로 정렬한다. 알파벳 순서로 정려되어 있음을 알수 있다.

[2]

select empno, ename, job
from emp
order by ename desc;

- [1]번에 있는 코드를 내림차순으로 정렬한 것이다. desc를 입력시 내림차순으로 정렬된다.

[3]

select empno, ename, job
from emp
order by 2 desc;

- 2번째 칼럼 ename을 내림차순으로 정렬하도록 한다.

- 숫자를 써서 몇번째 칼럼인지 지정할 수 있다.

- 하지만 가독성이 낮아지고 칼럼이 추가될시 값을 바꾸어야해서 좋은 방법이 아니다.

 

11) CASE

[1]

SELECT ename, job, sal,
		CASE job WHEN 'CLERK'  THEN  1.10*sal
				WHEN 'MANAGER' THEN  1.15*sal
				WHEN 'PRESIDENT'   THEN  1.20*sal
				ELSE sal
				END    REVISED_SALARY
FROM   emp;

- CASE를 통해 조건에 따른 결과를 출력할 수 있다.

- job 칼럼에서 CLERK일 경우 해당 열의 sal 값에 1.10을 곱하고, MANAGER는 11.5 그리고 PRESIDENT는 1.20을 공한다.

- 만약 해당 조건의 의외의 항목일 경우 해당 sal 값을 그대로 출력한다.

- END 옆에는 해당 칼럼의 별칭을 선언할 수 있다.

 

12) 문자열 함수

[1] trim

select trim(' Seoul, South Korea '); -- 공백제거
select trim(leading '0' from '0000002850');
-- ltrim()은 공백만 제거할 수 있으나 leading은 값을 특정할 수 있다.
select trim(trailing ',' from 'col1,col2,col3,');
-- rtrim()은 공백만 제거할 수 있으나 trailing은 값을 특정할 수 있다.

--> 결과

Seoul, South Korea
2850
col1,col2,col3

[2] substr

select substr('0123456',2); -- 2번째 숫자부터 시작한다.
select substr('0123456',2,4); -- 2번째 숫자부터 4개를 자른다.
select substr('0123456',-3); -- 뒤에서 3번째 글자부터 끝까지 자르기
select substr('0123456',-3,1); -- 뒤에서 3번째 글자부터 1글자 자르기
select substr('0123456' from -4 for 2); -- 뒤에서 4번째 글자부터 2글자 자르기
select substr('0123456', -4, 2); -- 뒤에서 4번째 글자부터 2글자 자르기

--> 결과

123456
1234
456
4
34
34

[3] length

select length('choi');
select length('최'); -- UTF-8 한글의 경우 한글자당 3바이트를 사용해 3으로 계산됨
select char_length('choi');
select char_length('최'); -- Character(문자)별 길이 계산시 이용

--> 결과

4
3
4
1

[4] lpad, rpad

select lpad('2500',9,'0'); -- 왼쪽으로 특정문자를 원하는 자리수만큼 넣는다.
select rpad('123-12-1',13,'*'); -- 오른쪽으로 특정문자를 원하는 자리수만큼 넣는다.

--> 결과

000002500
123-12-1*****

[5] concat

select concat('my','sql',8); -- 주어진 문자열을 연결한다.

--> 결과

mysql8

[6] lower, upper

select lower('Hello, World!'); -- 주어진 영문자를 소문자로 변환
select upper('Hello, World!'); -- 주어진 영문자를 대문자로 변환

--> 결과

hello, world!
HELLO, WORLD!

[7] like

select 'MySql8' like 'sql'; -- like구문은 부분적으로 일치하는 칼럼을 조회시 사용된다.
select 'MySql8' like '%sql%';
with height_list as(
    select 175 as height union all
    select 183 as height union all
    select 190 as height
)
select height like '18%' from height_list;

--> 결과

0
1
0
1
0

[8] replace

select replace('apple apple apple','apple','banana'); -- 주어진 문자열에서 특정값을 찾아 변환

--> 결과

banana banana banana

13) 조인

- 조인시킬 두 테이블

select * from emp;

select * from dept;

[1] CROSS JOIN

- 한쪽 테이블의 모든 행들과 다른 쪽 테이블의 모든 행을 조인시킨다.

select *
from emp cross join dept;

[2] INNER JOIN

- 가장 일반적인 조인이다.

- inner 생략이 가능하다.

- 두 테이블을 조인할 때, 두 테이블에 모두 지정한 열의 데이터가 있어야 한다.

select *
from emp, dept
where emp.deptno = dept.deptno;
-- 혹은
select *
from emp inner join dept
where emp.deptno = dept.deptno;

--> 결과

[2-1] INNER JOIN

select E.empno, E.ename, E.deptno, D.dname
from emp E inner join dept D
on E.deptno = D.deptno;

- where와 on 둘다 조건을 지정해 준다.

- on은 최초의 조인 조건을 지정할 때 쓰고, where는 추가 필터링이 필요시 추가한다.

--> 결과

ex 1)

select E.empno, E.ename, E.deptno, D.dname
from emp E inner join dept D
on E.deptno = D.deptno
where E.deptno = 20
and E.sal > 2000;

- on에서는 emp 테이블과 dept 테이블의 deptno 칼럼이 같을때의 조건이다.

- where에서는 부서번호(deptno)가 20이고 급여(sal)가 이상일 때의 조건을 가지고 있다.

--> 결과

ex 2)

select * from salgrade;

- 급여 등급에 관한 테이블이다.

--> 결과

- losal은 최소등급, hisal은 최대 등급, grade는 등급이다.

 

select E.ename, E.sal, S.grade
from emp E join salgrade S -- inner 생략가능
on E.sal between S.losal and S.HISAL;

- 이름, 급여, 등급을 출력한다.

--> 결과

[3] RIGHT OUTER JOIN

- OUTER JOIN은 조인 조건에 만족되지 않는 행까지 포함시켜야 한다.

- RIGHT OUTER JOIN은 오른쪽 테이블의 것이 전부 출력되어야 한다.

- LEFT일 경우 왼쪽 테이블에 맞우어야 하고 FULL은 LEFT와 OUTER가 합쳐진 것이다.

select E.empno, E.ename, D.deptno, D.dname
from emp E right outer join dept D -- outer 생략가능
on E.deptno = D.deptno;

--> 결과

가장 아래쪽 행에 NULL이 있다.

[4] SELF JOIN

- 자기 자신과 자시 자신이 조인하는 것이다.

-- 사번, 이름, 매니저 사번, 매니저 이름
select E.EMPNO, E.ENAME, M.EMPNO, M.ENAME
from emp E join emp M
on E.mgr = M.empno;

- 별칭이 E인 emp테이블의 사번과 이름, 별칭이 M인 emp테이블의 사번과 이름을 조인한다.

- 조건은 E의 매니저 번호(mgr), M의 직원번호가 같을 때이다.

--> 결과

[5] UNION

- 두 쿼리의 결과를 행으로 합치는 것이다.

- UNION은 중복된 열은 제거되고 데이터 정렬되어 나오지만, UNION ALL을 사용시 중복된 열까지 모두 출력된다.

select EMPNO, ENAME, JOB
from EMP
where JOB='CLERK'
UNION
select EMPNO, ENAME, JOB
from EMP
where JOB='SALESMAN';

--> 결과

14) CASE 예제 1

-- 이름, 업무, 급여, 등급(5 기술사, 4 특급기사, 3 일반기사, 2 기능사, 일반)
SELECT E.ename, E.job, E.sal, 
	CASE s.grade WHEN 5 THEN '기술사'
				WHEN 4 THEN '특급기사'
				WHEN 3 THEN '일반기사'
                WHEN 2 THEN '기능사'
				ELSE '일반'
				END '등급'
FROM emp E join salgrade S
on E.sal between S.losal and S.HISAL;

- case조건을 선언해 등급에 따라 등급명칭을 부여한다.

--> 결과

15) 연산

select avg(sal) from emp; -- 평균
select count(*) from emp; -- 갯수
select sum(sal) from emp; -- 함계
select max(sal) from emp; -- 최대
select min(sal) from emp; -- 최소
select stddev(sal) from emp; -- 표준편차 계산(NULL 값 제외)
select variance(sal) from emp; -- 분산

--> 결과

- 평균

2073.214285714286

- 갯수

14

- 합계

29025

- 최대

5000

- 최소

800

- 표준편차

1139.4886182952814

- 분산

1298434.3112244897

16) group by

- group by: 특정 칼럼을 기준으로 집계 함수를 사용한다.

[1]

select deptno, avg(sal)
from emp
group by deptno
order by avg(sal) desc;

- deptno 칼럼을 기준으로 사용한다.

- GROUP BY 절의 칼럼은 SELECT 절에 존재해야 사용할 수 있다.

- SELECT 절에서 집계 함수를 제외한 칼럼을 GROUP BY 절에 기술한다고 생각하면 된다.

--> 결과

[2]

select E.deptno, D.dname ,avg(E.sal)
from emp E join dept D
on E.deptno = D.deptno
group by E.deptno, D.dname
order by avg(E.sal) desc;

--> 결과

[3] having

- 평균급여가 2000달러 이상인 곳을 출력한다.,

select E.deptno, D.dname ,avg(E.sal)
from emp E join dept D
on E.deptno = D.deptno
-- where avg(E.sal)>2000
group by E.deptno, D.dname
-- group by 절이후에 where 가능, group by한 결과를 조건으로 범위설정시 where 못씀
having avg(sal)>2000
order by avg(E.sal) desc;

- WHERE 절에서는 집계함수를 사용 할 수 없다.

- HAVING 절은 집계함수를 가지고 조건비교를 할 때 사용한다.

- HAVING절은 GROUP BY절과 함께 사용이 된다.

--> 결과

17) 서브쿼리

- 서브쿼리: 하나의 SQL 문에 포함되어 있는 또 다른 SQL 문을 말한다.

- 단일 행 또는 복수 행 비교 연산자와 함께 사용 가능하지만 ORDER BY는 사용하지 못한다.

[1] scott 보다 월급이 더 많은 직원의 이름 출력

select sal
from emp
where ename='scott'; -- scott 월급

--> 결과

3000
select ename
from emp
where sal >(
	select sal
    from emp
    where ename='scott'
); -- 서브쿼리 이용

--> 결과

KING

[2]

select ename, sal, deptno
from emp
where ename=(select min(ename) from emp);

- 알파벳 순서상 가장 앞에 오는 이름에 대한 정보를 출력한다.

--> 결과

[3]

select ename, sal
from emp
where sal <(select avg(sal) from emp);

- 평균 월급보다 적게 받는 사람들을 출력한다.

--> 결과

[4] 같은 조건 join문으로 바꾸기

select ename, deptno
from emp
where deptno = (
	select deptno
    from dept
    where dname = 'SALES'
);

↓ join문으로 변환하기

select E.ename, E.deptno
from emp E join dept D
on E.deptno = D.deptno
where D.dname = 'SALES';

--> 결과

[5] IN

select ename, sal, deptno
from emp
where ename in (
	select min(ename)
	from emp
	group by deptno
); -- =은 안되고 in이 가능

- in에 있는 서브쿼리가 먼저 실행된다.

- 부서별로 알파벳이 빠른순서로 데이터를 출력한다.

--> 결과

[6]

select ename, sal, deptno
from emp E
where sal >(
	select avg(sal)
    from emp
    where deptno = E.deptno
);

- 부서번호를 통해서 평균 임금을 산출한다.

- 평균 임금보다 클 경우의 데이터를 출력한다.

--> 결과

[7]

select deptno, empno, ename, sal
from emp E
where E.sal = (
	select max(sal)
    from emp
    where deptno= E.deptno
);

- 부서별 최고 급여를 받는 직원의 부서코드, 사번, 이름, 급여를 출력

--> 결과

18) CTE(Common Table Expression)

- 쿼리를 통해 만들어낸 임시적인 데이터 세트이다.

- 기존의 뷰나 파생 테이블, 임시 테이블 등으로 사용되는 것들을 대신할 수 있고, 보다 더 간결한 표현을 사용할 수 있따는 장점이 있다.

WITH 테이블 이름 AS (테이블 만들 쿼리문)

[1]

with max_sal as ( -- 가독성을 더 좋게 만들어줌
	select deptno, max(sal)as msal
	from emp
    group by deptno
)
select E.deptno, E.empno, E.ename, E.sal
from emp E join max_sal
on E.deptno = max_sal.DEPTNO
where E.sal = max_sal.msal;

- 부서별 최대임금을 받는 사람들을 뽑는다.

--> 결과

[2] 평균 급여가 가장 높은 부서코드와 평균급여를 출력

with avg_cte as (
	select deptno, avg(sal) as avg_sal
	from emp
	group by deptno
)
select deptno, avg_sal
from avg_cte
where avg_sal = ( select max(avg_sal) from avg_cte);

--> 결과

19) View

- 테이블과 동일하게 사용되는 개체이다.

-  SQL에서 하나 이상의 테이블 에서 원하는 모든 데이터를 선택하여, 그들을 사용자 정의하여 나타낸 것이다.

[1]

create view AVG_VIEW as
select deptno, avg(sal) as avg_sal
from emp
group by deptno; -- 부서별로의 평균임금의 view AVG_VIEW를 생성한다.

select deptno, avg_sal
from AVG_VIEW
where avg_sal = (select max(avg_sal) from AVG_VIEW);
-- AVG_VIEW를 이용해 평균임금이 가장큰 부서번호와 평균임금을 출력한다.

--> 결과