SQL에서 JOIN이란 하나의 테이블에서 데이터를 조회 하는 것이 아닌 두 개 이상의 테이블과 연결 또는 결합하여 데이터를 출력하는 경우 사용하는 기능이다.
일반적으로 프로젝트를 경험하게 되면 상당수의 SQL문들이 JOIN으로 이루어져 있다. JOIN은 관계형 데이터 베이스에서 가장 큰 장점이면서 핵심적인 기능이라고 말할 수 있다.
일반적인 경우 행들은 PRIMARY KEY(PK) 와 FOREIGN KEY(FK) 값의 연관에 의해 JOIN이 성립되지만 관계가 없는 경우에도 논리적인 값들의 연관만으로 JOIN이 성립될 수 있다.
EQUI JOIN을 하기전에 JOIN을 위해서는 두 개 이상의 테이블이 존재해야한다. 먼저 JOIN에 필요한 테이블을 생성한다.
테스트 DB서버가 있다면 DDL과 DML을 입력하여 테이블을 구성한 후 직접 JOIN문을 실행해보는 것을 추천한다.
1. 선수 테이블 (PLAYER)
CREATE TABLE "PLAYER"
( "PLAYER_ID" CHAR(7 BYTE),
"PLAYER_NAME" VARCHAR2(20 BYTE),
"TEAM_ID" CHAR(3 BYTE),
"E_PLAYER_NAME" VARCHAR2(40 BYTE),
"NICKNAME" VARCHAR2(30 BYTE),
"JOIN_YYYY" CHAR(4 BYTE),
"POSITION" VARCHAR2(10 BYTE),
"BACK_NO" NUMBER(2,0),
"NATION" VARCHAR2(20 BYTE),
"BIRTH_DATE" DATE,
"SOLAR" CHAR(1 BYTE),
"HEIGHT" NUMBER(3,0),
"WEIGHT" NUMBER(3,0)
);
Insert into PLAYER (PLAYER_ID,PLAYER_NAME,TEAM_ID,E_PLAYER_NAME,NICKNAME,JOIN_YYYY,POSITION,BACK_NO,NATION,BIRTH_DATE,SOLAR,HEIGHT,WEIGHT) values ('2002007','박지성','K07',null,'Two Heart',null,'MF',7,'대한민국',null,null,191,73);
Insert into PLAYER (PLAYER_ID,PLAYER_NAME,TEAM_ID,E_PLAYER_NAME,NICKNAME,JOIN_YYYY,POSITION,BACK_NO,NATION,BIRTH_DATE,SOLAR,HEIGHT,WEIGHT) values ('2002010','이청용','K05',null,'BlueDragon','2002','MF',17,'몽골',null,'1',180,69);
Insert into PLAYER (PLAYER_ID,PLAYER_NAME,TEAM_ID,E_PLAYER_NAME,NICKNAME,JOIN_YYYY,POSITION,BACK_NO,NATION,BIRTH_DATE,SOLAR,HEIGHT,WEIGHT) values ('2002011','조현우','K06',null,'빛현우','2002','GK',1,'루마니아',null,'1',185,64);
Insert into PLAYER (PLAYER_ID,PLAYER_NAME,TEAM_ID,E_PLAYER_NAME,NICKNAME,JOIN_YYYY,POSITION,BACK_NO,NATION,BIRTH_DATE,SOLAR,HEIGHT,WEIGHT) values ('2002017','기성용','K07',null,'용용','2004','MF',14,'브라질',null,null,181,72);
Insert into PLAYER (PLAYER_ID,PLAYER_NAME,TEAM_ID,E_PLAYER_NAME,NICKNAME,JOIN_YYYY,POSITION,BACK_NO,NATION,BIRTH_DATE,SOLAR,HEIGHT,WEIGHT) values ('2002030','손흥민','K05',null,'SON','2010','AMC',7,'콜롬비아',null,null,178,79);
Insert into PLAYER (PLAYER_ID,PLAYER_NAME,TEAM_ID,E_PLAYER_NAME,NICKNAME,JOIN_YYYY,POSITION,BACK_NO,NATION,BIRTH_DATE,SOLAR,HEIGHT,WEIGHT) values ('2002031','김민재','K05',null,'KIM','2012','DF',7,'중국',null,null,193,83);
Insert into PLAYER (PLAYER_ID,PLAYER_NAME,TEAM_ID,E_PLAYER_NAME,NICKNAME,JOIN_YYYY,POSITION,BACK_NO,NATION,BIRTH_DATE,SOLAR,HEIGHT,WEIGHT) values ('2005008','이승우','K08',null,'날쌘돌이','2002','ST',10,'대한민국',null,null,171,73);
Insert into PLAYER (PLAYER_ID,PLAYER_NAME,TEAM_ID,E_PLAYER_NAME,NICKNAME,JOIN_YYYY,POSITION,BACK_NO,NATION,BIRTH_DATE,SOLAR,HEIGHT,WEIGHT) values ('2000011','안정환','K05',null,'반지',null,null,13,'대한민국',null,null,171,80);
Insert into PLAYER (PLAYER_ID,PLAYER_NAME,TEAM_ID,E_PLAYER_NAME,NICKNAME,JOIN_YYYY,POSITION,BACK_NO,NATION,BIRTH_DATE,SOLAR,HEIGHT,WEIGHT) values ('2004012','황선홍','K08',null,'황소','2002','ST',11,'대한민국',null,null,178,73);
Insert into PLAYER (PLAYER_ID,PLAYER_NAME,TEAM_ID,E_PLAYER_NAME,NICKNAME,JOIN_YYYY,POSITION,BACK_NO,NATION,BIRTH_DATE,SOLAR,HEIGHT,WEIGHT) values ('2001022','설기현','K01',null,'설','2002','ST',15,'대한민국',null,null,176,77);
Insert into PLAYER (PLAYER_ID,PLAYER_NAME,TEAM_ID,E_PLAYER_NAME,NICKNAME,JOIN_YYYY,POSITION,BACK_NO,NATION,BIRTH_DATE,SOLAR,HEIGHT,WEIGHT) values ('2002033','이천수','K13',null,'번개','2002','MF',2,'대한민국',null,null,183,80);
Insert into PLAYER (PLAYER_ID,PLAYER_NAME,TEAM_ID,E_PLAYER_NAME,NICKNAME,JOIN_YYYY,POSITION,BACK_NO,NATION,BIRTH_DATE,SOLAR,HEIGHT,WEIGHT) values ('2003004','황희찬','K14',null,'황','2002','MF',3,'대한민국',null,null,187,81);
Insert into PLAYER (PLAYER_ID,PLAYER_NAME,TEAM_ID,E_PLAYER_NAME,NICKNAME,JOIN_YYYY,POSITION,BACK_NO,NATION,BIRTH_DATE,SOLAR,HEIGHT,WEIGHT) values ('2005002','이강인','K15',null,'유망주','2002','MF',94,'대한민국',null,null,188,83);
Insert into PLAYER (PLAYER_ID,PLAYER_NAME,TEAM_ID,E_PLAYER_NAME,NICKNAME,JOIN_YYYY,POSITION,BACK_NO,NATION,BIRTH_DATE,SOLAR,HEIGHT,WEIGHT) values ('1002341','박주호','K01',null,'슈퍼맨','2002','DF',19,'대한민국',null,null,183,81);
Insert into PLAYER (PLAYER_ID,PLAYER_NAME,TEAM_ID,E_PLAYER_NAME,NICKNAME,JOIN_YYYY,POSITION,BACK_NO,NATION,BIRTH_DATE,SOLAR,HEIGHT,WEIGHT) values ('1234151','김승규','K11',null,'김','2002','GK',21,'대한민국',null,null,179,60);
Insert into PLAYER (PLAYER_ID,PLAYER_NAME,TEAM_ID,E_PLAYER_NAME,NICKNAME,JOIN_YYYY,POSITION,BACK_NO,NATION,BIRTH_DATE,SOLAR,HEIGHT,WEIGHT) values ('2019292','이재성','K09',null,'이','2002','DF',23,'대한민국',null,null,182,89);
2. 팀 테이블 (TEAM)
CREATE TABLE "TEAM"
( "TEAM_ID" VARCHAR2(3 BYTE),
"TEAM_NAME" VARCHAR2(20 BYTE),
"REGION_NAME" VARCHAR2(10 BYTE),
"STADIUM_ID" VARCHAR2(5 BYTE)
);
Insert into TEAM (TEAM_ID,TEAM_NAME,REGION_NAME,STADIUM_ID) values ('K03','스틸러스','포항','C06');
Insert into TEAM (TEAM_ID,TEAM_NAME,REGION_NAME,STADIUM_ID) values ('K05','현대모터스','전북','D03');
Insert into TEAM (TEAM_ID,TEAM_NAME,REGION_NAME,STADIUM_ID) values ('K08','일화천마','성남','B02');
Insert into TEAM (TEAM_ID,TEAM_NAME,REGION_NAME,STADIUM_ID) values ('K07','드래곤즈','전남','D01');
Insert into TEAM (TEAM_ID,TEAM_NAME,REGION_NAME,STADIUM_ID) values ('K09','FC서울','서울','B05');
Insert into TEAM (TEAM_ID,TEAM_NAME,REGION_NAME,STADIUM_ID) values ('K04','유나이티드','인천','B01');
Insert into TEAM (TEAM_ID,TEAM_NAME,REGION_NAME,STADIUM_ID) values ('K11','경남FC','경남','C05');
Insert into TEAM (TEAM_ID,TEAM_NAME,REGION_NAME,STADIUM_ID) values ('K01','울산현대','울산','C04');
Insert into TEAM (TEAM_ID,TEAM_NAME,REGION_NAME,STADIUM_ID) values ('K02','삼성블루윙즈','수원','B04');
Insert into TEAM (TEAM_ID,TEAM_NAME,REGION_NAME,STADIUM_ID) values ('K12','광주상무','광주','A02');
Insert into TEAM (TEAM_ID,TEAM_NAME,REGION_NAME,STADIUM_ID) values ('K06','아이파크','부산','C02');
Insert into TEAM (TEAM_ID,TEAM_NAME,REGION_NAME,STADIUM_ID) values ('K13','강원FC','강원','A03');
Insert into TEAM (TEAM_ID,TEAM_NAME,REGION_NAME,STADIUM_ID) values ('K14','제주FC','제주','A04');
Insert into TEAM (TEAM_ID,TEAM_NAME,REGION_NAME,STADIUM_ID) values ('K15','대구FC','대구','A05');
Insert into TEAM (TEAM_ID,TEAM_NAME,REGION_NAME,STADIUM_ID) values ('K10','시티즌','대전','D02');
3. 경기장 테이블 (STADIUM)
CREATE TABLE "STADIUM"
( "STADIUM_ID" VARCHAR2(5 BYTE),
"STADIUM_NAME" VARCHAR2(40 BYTE),
"SEAT_COUNT" NUMBER,
"HOMETEAM_ID" VARCHAR2(4 BYTE),
"HOMECHECK" VARCHAR2(4 BYTE)
);
Insert into STADIUM (STADIUM_ID,STADIUM_NAME,SEAT_COUNT,HOMETEAM_ID,HOMECHECK) values ('D03','전주월드컵경기장',28000,'K05','HOME');
Insert into STADIUM (STADIUM_ID,STADIUM_NAME,SEAT_COUNT,HOMETEAM_ID,HOMECHECK) values ('B02','성남종합운동장',27000,'K08','HOME');
Insert into STADIUM (STADIUM_ID,STADIUM_NAME,SEAT_COUNT,HOMETEAM_ID,HOMECHECK) values ('C06','포항스틸야드',25000,'K03','HOME');
Insert into STADIUM (STADIUM_ID,STADIUM_NAME,SEAT_COUNT,HOMETEAM_ID,HOMECHECK) values ('D01','광양전용경기장',20009,'K05','HOME');
Insert into STADIUM (STADIUM_ID,STADIUM_NAME,SEAT_COUNT,HOMETEAM_ID,HOMECHECK) values ('B05','서울월드컵경기장',66806,'K09',null);
Insert into STADIUM (STADIUM_ID,STADIUM_NAME,SEAT_COUNT,HOMETEAM_ID,HOMECHECK) values ('B01','인천월드컵경기장',35000,'K04','HOME');
Insert into STADIUM (STADIUM_ID,STADIUM_NAME,SEAT_COUNT,HOMETEAM_ID,HOMECHECK) values ('C05','창원종합운동장',27085,'K01',null);
Insert into STADIUM (STADIUM_ID,STADIUM_NAME,SEAT_COUNT,HOMETEAM_ID,HOMECHECK) values ('C04','울산문수경기장',46102,'K01',null);
Insert into STADIUM (STADIUM_ID,STADIUM_NAME,SEAT_COUNT,HOMETEAM_ID,HOMECHECK) values ('D02','대전월드컵경기장',41000,'K10','HOME');
Insert into STADIUM (STADIUM_ID,STADIUM_NAME,SEAT_COUNT,HOMETEAM_ID,HOMECHECK) values ('B04','수원월드컵경기장',50000,'K02','HOME');
Insert into STADIUM (STADIUM_ID,STADIUM_NAME,SEAT_COUNT,HOMETEAM_ID,HOMECHECK) values ('A02','광주월드컵경기장',40245,'K12',null);
Insert into STADIUM (STADIUM_ID,STADIUM_NAME,SEAT_COUNT,HOMETEAM_ID,HOMECHECK) values ('C02','부산아시아드경기장',30000,'K06','HOME');
Insert into STADIUM (STADIUM_ID,STADIUM_NAME,SEAT_COUNT,HOMETEAM_ID,HOMECHECK) values ('A03','강릉종합경기장',30000,'K13',null);
Insert into STADIUM (STADIUM_ID,STADIUM_NAME,SEAT_COUNT,HOMETEAM_ID,HOMECHECK) values ('A04','제주월드컵경기장',42256,'K14',null);
Insert into STADIUM (STADIUM_ID,STADIUM_NAME,SEAT_COUNT,HOMETEAM_ID,HOMECHECK) values ('A05','대구월드컵경기장',66422,'K15',null);
Insert into STADIUM (STADIUM_ID,STADIUM_NAME,SEAT_COUNT,HOMETEAM_ID,HOMECHECK) values ('F01','대구시민경기장',30000,'K15','HOME');
Insert into STADIUM (STADIUM_ID,STADIUM_NAME,SEAT_COUNT,HOMETEAM_ID,HOMECHECK) values ('F02','부산시민경기장',30000,'K06',null);
Insert into STADIUM (STADIUM_ID,STADIUM_NAME,SEAT_COUNT,HOMETEAM_ID,HOMECHECK) values ('F03','일산경기장',20000,'K09','HOME');
Insert into STADIUM (STADIUM_ID,STADIUM_NAME,SEAT_COUNT,HOMETEAM_ID,HOMECHECK) values ('F04','마산경기장',20000,'K02',null);
Insert into STADIUM (STADIUM_ID,STADIUM_NAME,SEAT_COUNT,HOMETEAM_ID,HOMECHECK) values ('F05','안양경기장',20000,'K02','HOME');
기본 PK FK 관계는
1) PLAYER.TEAM_ID (PK) => TEAM.TEAM_ID (FK)
2) TEAM.STADIUM_ID (PK) => STADIUM.STADIUM_ID (FK)
관계가 성립되어야 하지만 원할한 조인을 위해 PK FK 관계설정은 생략하였다.
테이블을 생성하였으니 EQUI JOIN에 대해 알아보고 JOIN문을 실행시켜보자.
EQUI(등가) JOIN은 두 개의 테이블 간에 칼럼 값들이 서로 정확하게 일치하는 경우에 사용되는 방법으로 대부분 PK ↔ FK의 관계를 기반으로 한다. 그러나 일반적으로 테이블 설계 시에 나타난 PK ↔ FK의 관계를 이용하는 것이지 반드시 PK ↔ FK의 관계로만 EQUI JOIN이 성립하는 것은 아니다.
JOIN의 조건은 WHERE 절에 기술하게 되는데 “=” 연산자를 사용해서 표현한다.
즉, EQUI JOIN은 두 개의 테이블에 값이 일치하는 데이터가 존재하는 칼럼을 기준으로 각 테이블에 대한 데이터를 조회하는 것이라고 할 수 있다.
위 2개의 테이블에는 TEAM_ID라는 칼럼안에 같은 데이터들이 존재한다. 이렇게 같은 데이터를 비교하여 서로 다른 2개의 테이블의 정보를 조회하는 것을 EQUI조인이라고 할 수 있다.
이제 JOIN문을 실행시켜보자.
예졔) 선수 테이블과 팀 테이블을 조인하여 선수이름, 백넘버, 팀이름, 팀 연고지를 조회하시오.
EQUI JOIN을 할 수있는 방법은 2가지 방법이 있다.
1) JOIN이라는 명령문을 EQUI JOIN
SELECT
A.PLAYER_NAME,
A.BACK_NO,
A.TEAM_ID,
B.TEAM_NAME,
B.REGION_NAME
FROM
PLAYER A ,
TEAM B
WHERE
A.TEAM_ID = B.TEAM_ID;
2) INNER JOIN 명령문을 기재한 EQUI JOIN
SELECT
A.PLAYER_NAME,
A.BACK_NO,
A.TEAM_ID,
B.TEAM_NAME,
B.REGION_NAME
FROM
PLAYER A INNER JOIN TEAM B
ON
A.TEAM_ID = B.TEAM_ID;
참고로
WHERE 과 ON 절은 서로 다른 의미를 가지고 있지만 위의 예시에서는 같은 역할을 한다고 생각하면 된다.
추후에 WHERE과 ON의 차이점에 대해서 포스팅하도록 하겠다.
실행을 시키게 되면 TEAM_ID라는 공통칼럼을 기준으로 PLAYER 테이블에 존재하는 PLAYER_NAME, BACK_NO 데이터와 TEAM 테이블에 존재하는 TEAM_NAME, REGION_NAME 데이터를 한 결과창에서 확인할 수 있다.
'SQL' 카테고리의 다른 글
[SQL] Non EQUI JOIN (0) | 2019.08.05 |
---|