[12일차] SQL문 연산자, 정규화

2026. 6. 7. 21:33KDT/2. MySQL

11일차 4. SQL 명령어 사용의 DML에 이어서

 

1. DML (이어서)

  • 11일차에 만들었던 member 테이블이 잘 있나 확인하고
  • 테이블에 gender 컬럼을 추가하자
컬럼명 설명
gender  varchar(10), not null
  • 컬럼들이 잘 생성되었는지 select문으로 확인해보자
-- member 테이블 확인
desc member;

-- gender 컬럼 추가
alter table member add gender varchar(10) not null;

-- member 테이블 데이터 확인 -> 컬럼만 조회됨 (데이터가 없으니까)
select * from member;

 

  • 회원 가입 : member 테이블에 회원 정보를 삽입해보자
insert into member (userid, userpw, name, hp, email, ssn1, ssn2, zipcode, address1, address2, address3, gender) values ('apple', '1111', '김사과', '010-1111-1111', 'apple@apple.com', '001011', '4011111', '12345', '서울 서초구', '양재동', '111-11', '여자');
insert into member (userid, userpw, name, hp, email, ssn1, ssn2, zipcode, address1, address2, address3, gender) values ('banana', '2222', '반하나', '010-2222-2222', 'banana@banana.com', '001011', '4011111', '12345', '서울 서초구', '양재동', '111-11', '여자');
insert into member (userid, userpw, name, hp, email, ssn1, ssn2, zipcode, address1, address2, address3, gender) values ('orange', '3333', '오렌지', '010-3333-3333', 'orange@orange.com', '001011', '4011111', '12345', '서울 서초구', '양재동', '111-11', '남자');
insert into member (userid, userpw, name, hp, email, ssn1, ssn2, zipcode, address1, address2, address3, gender) values ('melon', '4444', '이메론', '010-4444-4444', 'melon@melon.com', '001011', '4011111', '12345', '서울 서초구', '양재동', '111-11', '남자');
insert into member (userid, userpw, name, hp, email, ssn1, ssn2, zipcode, address1, address2, address3, gender) values ('cherry', '5555', '채리', '010-5555-5555', 'cherry@cherry.com', '001011', '4011111', '12345', '서울 서초구', '양재동', '111-11', '여자');
  • member 테이블의 point 컬럼을 수정해보자
-- idx가 5인 데이터에 대해 point를 0으로 수정
update member set point = 0 where idx = 5;

-- 모든 데이터에 대해 point를 50점 추가
update member set point = point + 50;

-- idx가 2인 데이터에 대해 point를 100점 추가
update member set point = point + 100 where idx = 2;
  • select문으로 데이터를 조회해보자
select 100;
select 100 + 50;
select 100 + 50 as 덧셈;
select 100 + 50 as '덧셈 연산';	-- 띄어쓰기는 '로 묶기
select '';		-- 빈 문자열(빈 문자가 들어가 있는 것)
select null;	-- 데이터가 없음
select 100 + '';
select 100 + null;	-- null과의 연산은 무조건 결과가 null

2. SQL의 연산자

1. 산술 연산자 : + - * / mod(나머지) div(몫)

2. 비교 연산자 : =   <   >   <=   >=   <>

3. 대입 연산자 : =

4. 논리 연산자 : and or not xor

5. is 연산자 : 양쪽의 피연산자가 모두 같으면 true(데이터가 출력), 아니면 false(데이터가 출력되지 않음)

6. between A and B : A보다는 크거나 같고, B보다는 작거나 같으면 true, 아니면 false

7. in 연산자 : 매개변수로 전달된 리스트에 값이 존재하면 true, 아니면 false

8. like 연산자 : 패턴으로 문자열을 검색하여 값이 존재하면 true, 아니면 false


3. SELECT문과 연산자 연습하기

  • 비교 연산자
-- 포인트가 150이상인 멤버의 아이디, 이름, 포인트를 검색
select userid, name, point from member where point >= 150;
-- 포인트가 150이상이고, 200이하인 멤버의 아이디, 이름, 포인트, 성별을 검색
select userid, name, point, gender from member where point >= 150 and point <= 200;
select userid, name, point, gender from member where point between 150 and 200;
  • 두 가지 조건(and)을 사용한 로그인 구현
-- 로그인
select userid from member where userid = 'apple' and userpw = '1111';	-- 성공
select userid from member where userid = 'apple' and userpw = '1112';	-- 실패
  • 논리 연산자(or)와 in 연산자
-- 이름이 김사과, 반하나, 오렌지인 사람의 모든 정보를 검색
select * from member where name = '김사과' or name = '반하나' or name = '오렌지';
select * from member where name in ('김사과', '반하나', '오렌지');
  • member 테이블에 데이터 하나 추가
insert into member (userid, userpw, name, hp, email, ssn1, ssn2, zipcode, address1, address2, address3, gender, regdate) values ('berry', '6666', '배애리', '010-6666-6666', 'berry@berry.com', '001011', '4011111', '12345', '서울 서초구', '양재동', '111-11', '여자', null);
  • is 연산자와 is not 연산자
-- regdate가 null인 멤버를 검색
-- select * from member where regdate = null;	-- 불가능
select * from member where regdate is null;
select * from member where regdate is not null;
  • like 연산자
-- 아이디가 a로 시작하는 멤버의 정보를 검색
select * from member where userid like 'a%';
-- 아이디가 a로 끝나는 멤버의 정보를 검색
select * from member where userid like '%a';
-- 아이디가 a를 포함하는 멤버의 정보를 검색
select * from member where userid like '%a%';
-- 이메일이 '.com'으로 끝나는 멤버의 정보를 검색
select * from member where email like '%.com';
-- 이름이 3자인 멤버를 검색
select * from member where name like '___';
-- 이름 첫 글자가 '김'씨이며 3자인 멤버를 검색
select * from member where name like '김__';

4. order by (정렬)

  • 오름차순(asc)가 기본값
select * from member order by idx;	-- 오름차순 asc 생략
select * from member order by idx desc;	-- 내림차순
-- 멤버를 포인트 순으로 정렬
select * from member order by point desc;
-- 멤버를 포인트 순으로 정렬. 단 포인트가 같으면 가입 최신순으로 정렬
select * from member order by point desc, regdate desc;

5. limit

  • 일부 row(레코드)를 검색
  • limit 검색할 로우의 개수, limit 시작로우(인덱스) 가져울 로우의 개수
select * from member limit 2;
select * from member limit 2, 3;
-- 멤버에서 포인트순으로 내림차순 정렬하고 포인트가 같다면 가입순으로 내림차순 한 뒤 top 3를 검색
select * from member order by point desc, regdate desc limit 3;

6. group by

  • 사용 방법
select 그룹을 맺을 컬럼 또는 집계함수 from 테이블 group by 그룹을 맺을 컬럼
select 그룹을 맺을 컬럼 또는 집계함수 from 테이블 group by 그룹을 맺을 컬럼 having 그룹에 대한 조건
  • 그룹을 지어 조회해보자
-- 성별로 그룹을 지어 성별을 조회
select gender from member group by gender;

-- 성별로 그룹을 지어 성별과 idx 수를 조회
select gender, count(idx) as 인원수 from member group by gender;

-- 성별로 그룹을 지어 성별이 여자인 데이터의 성별과 idx 수를 조회
select gender, count(idx) as 인원수 from member group by gender having gender = '여자';
select gender, count(idx) as 인원수 from member where gender = '여자' group by gender;

-- 성별로 그룹을 맺고 인원수가 3명 이상인 성별을 검색
select gender, count(idx) as 인원수 from member group by gender having count(idx) >= 3;
select gender, count(idx) as 인원수 from member group by gender having 인원수 >= 3;
select gender from member group by gender having count(idx) >= 3;
  • 복잡한 sql을 구현해보자
/*
	멤버 중 포인트가 50 이상인 멤버 중에서 성별로 그룹을 나눈 뒤,
	각 그룹의 포인트 평균을 구하고 평균의 포인트가 100 이상인 성별을 출력
    (단 성별이 남자, 여자 모두 출력된다면 포인트가 높은 성별을 우선으로 출력)
*/
select gender, avg(point) as 평균포인트 from member where point >= 50 group by gender having avg(point) >= 100 order by avg(point) desc;

7. 정규화 Normalization

  • 데이터베이스 테이블을 효율적으로 구조화하는 작업
  • 중복 데이터를 줄이고, 데이터가 꼬이지 않게 테이블을 나누는 과정
  • 데이터 무결성 유지, 유지보수 편리성 증가

# 정규화 단계

  1. 제1정규형(1NF) : 하나의 칸에는 하나의 값만 들어가야 함 
    예) MySQL, Python을 한 칸에 넣을 수 없음
  2. 제2정규형(2NF) : 1NF 만족, 기본키 전체에 완전 종속
  3. 제3정규형(3NF) : 2NF 만족, 이행적 종속 제거
    * 이행적 종속 :
        학번 -> 학과 번호
        학과 번호 -> 학과명
        학번 -> 학과명 : 간접 연결을 이행적 종속이라고 함 

# 아래 테이블을 만들려고 하는데, 정규화해서 만들어보자 (필요한 데이터는 추가해서 만들어보자)

create table student_course (
    student_id INT,
    student_name VARCHAR(50),
    course_name VARCHAR(50),
    professor_name VARCHAR(50),
    professor_phone VARCHAR(20)
);
-- 학생 student
create table student (
	student_id int primary key,
    student_name varchar(20)
);
-- 교수 professor
create table professor (
	professor_id int primary key,
	professor_name varchar(20),
    professor_phone varchar(20)
);
-- 과목 course
create table course (
	course_id int primary key,
    course_name varchar(50),
    professor_id int,
    foreign key (professor_id) references professor(professor_id)
);
-- drop table enroll;
-- 수강 enroll
create table enroll (
	student_id int,	
    course_id int,
	foreign key(student_id) references student(student_id),
    foreign key(course_id) references course(course_id),
    primary key(student_id, course_id)
);

8. join

  • 종류
    1. inner join : 양쪽 테이블에 모두 있는 데이터에 대해 join
    2. left join : left에 있는 데이터에 대해서만 join (빈 곳은 NaN으로 채움)
    3. right join : right에 있는 데이터에 대해서만 join (빈 곳은 NaN으로 채움)
    4. cross join : 모든 경우에 대해 join
  • 새로운 테이블 profile을 만들자
create table profile(
	idx int not null,
    height double,
    weight double,
    mbti varchar(10),
    foreign key(idx) references member(idx)
);
  • profile 테이블에 데이터를 채우자
insert into profile values (1, 160, 50, 'ISTJ');
insert into profile values (3, 170, 70, 'ESTP');
insert into profile values (4, 175, 80, 'ENFJ');
insert into profile values (6, 175, 80, 'ENFJ');
-- insert into profile values (7, 175, 80, 'ENFJ'); 외래키 제약조건 위배
  • member 테이블과 profile 테이블을 join 해보자
-- inner join
select member.idx, userid, name, gender, mbti from member inner join profile 
on member.idx = profile.idx;
select m.idx, m.userid, m.name, m.gender, p.mbti from member as m 
inner join profile as p on m.idx = p.idx;

-- left join
select m.idx, m.userid, m.name, m.gender, p.mbti from member as m 
left join profile as p on m.idx = p.idx;

-- right join
select m.idx, m.userid, m.name, m.gender, p.mbti from member as m 
right join profile as p on m.idx = p.idx;

-- cross join
select userid, name, gender, mbti from member
cross join profile;

 

'KDT > 2. MySQL' 카테고리의 다른 글

[14일차-1] 뷰  (0) 2026.06.09
[13일차] 서브 쿼리, 사용자계정(작성중)  (1) 2026.06.08
[11일차] MySQL, SQL명령어(DDL, DML)  (0) 2026.06.04