계층형 조회가 무엇을 위해 하는 것인지 잘 알아두자
self join
과 함께 하나의 테이블에 동일한 의미를 갖는 ㅋ러럼이 2개 이상 존재하는 경우에 사용이 가능함하나의 컬럼에서 연관된 컬럼을 쫓아가면서 데이터를 조회하는 것
MILLER JAMES TOM MINO 일 때(직급이),
MILLER에서 MINO까지 조회하고자 하는 경우 또는 반대인 경우
MILLERMINO, JAMESMINO 는 다르다. 즉 SQL을 다르게 짜야 한다.
WHERE
: 조건START WITH
: 계층 구조를 지정CONNECT BY
: 연결 관계를 설정
SELECT MAX(LEVEL) FROM EMP START WITH MGR IS NULL CONNECT BY PRIOR EMPNO=MGR;
CONNECT BY 가 추가되면 LEVEL이라는 컬럼이 자동으로 생성됩니다.
SELECT ENAME, EMPNO, MGR, CONNECT_BY_ISLEAF FROM EMP START WITH UPPER(JOB)='PRESIDENT' CONNECT BY PRIOR EMPNO=MGR;
PRESIDENT 인 행의 empno가 mgr로 사용 되는 것이 있느냐?
-- JONES부터 상관을 조회 SELECT ENAME, EMPNO, MGR, CONNECT_BY_ISLEAF FROM EMP START WITH ENAME='JONES' CONNECT BY PRIOR MGR=EMPNO;
해당 시작점부터의 상관 번호를 empno로 가지는 인원이 있느냐?
ROWID
,ROWNUM
이라는 컬럼을 제공합니다.-- ROWID를 알아보자. SELECT ROWID, ENAME FROM EMP;
이거 써먹기 좋은 곳이 존재합니다.
- 중복 제거에 유용합니다.
- 여러 컬럼을 조회해야 하는데, 그 중 하나의 컬럼의 중복을 제거해서 출력하고자 하는 경우
EMP 테이블에서 DEPTNO별로 한 명의 DEPTNO와 ENAME을 조회해보자.
- 어려운 문제야 😢
-- EMP 테이블에서 DEPTNO별로 한 명의 DEPTNO와 ENAME을 조회해보자. -- DISTINCT 는 여러 개의 컬럼이 작성된다면 모든 컬럼의 값이 같아야 제거 SELECT DISTINCT ENAME, DEPTNO FROM EMP; -- GROUPT BY는 그룹화하지 않은 컬럼을 SELECT 절에 출력할 수 없습니다. SELECT DEPTNO, ENAME FROM EMP GROUP BY DEPTNO; --ERROR -- 다른 컬럼을 사용하지 않고, 그룹화 한 후 ROWID가 가장 큰 데이터를 추출 SELECT DEPTNO, ENAME FROM EMP WHERE ROWID IN (SELECT MAX(ROWID) FROM EMP GROUP BY DEPTNO);
-- 행 번호 조회 SELECT ROWNUM, ENAME FROM EMP;
이건 쉽지만, ROWNUM을 이용한 조건을 만들 때는 주의를 해야 한다.
-- 이건 나오지만 SELECT ROWNUM, ENAME FROM EMP WHERE ROWNUM<3; -- 이건 절대 못나온다. SELECT ROWNUM, ENAME FROM EMP WHERE ROWNUM>3;
아직 WHERE절을 빠져나오지 못했는데 틀려서 계속 ROWNUM을 1번만 만든다.
-- 급여가 많은 순으로 조회해보자. SELECT * FROM EMP ORDER BY SAL DESC; -- 5개만 가져오고 싶다. SELECT * FROM EMP ORDER BY SAL DESC OFFSET 0 ROWS FETCH NEXT 5 NEXT ONLY;
-- 생성 CREATE SYNONYM 이름 FOR 기본객체이름; -- 삭제 DROP SYNONYM 이름;
-- EMP 테이블에 사원이라는 SYNONYM을 생성 CREATE SYNONYM 사원 FOR EMP; SELECT * FROM 사원; SELECT * FROM EMP;
별명이기에 새로운 이름 부여가 아니기 때문에 기존 이름도 사용 가능
CREATE SEQUENCE 이름 [START WITH 초기값] [INCREMENT BY 증감값] [MAXVALUE(최대값)|NOMAXVALUE] [MINVALUE(최소값)] [CYCLE|NOCYCLE] [CACHE 개수|NOCACHE];
이름.CURRVAL
: 현재 값, NEXTVAL을 한 번은 호출해야 사용 가능이름.NEXTVAL
: 다음 값DROP SEQUENCE 이름;
-- SEQUENCE CREATE SEQUENCE DEPT_SEQ START WITH 1000 INCREMENT BY 10; -- 값 확인하기 SELECT DEPT_SEQ.NEXVAL FROM DUAL; -- 오라클은 DUAL이라는 가짜 테이블을 써줘야함 -- SEQUENCE를 이용한 데이터 삽입 INSERT INTO DEPT(DEPTNO, DNAME, LOC) VALUES(DEPT_SEQ.NEXTVAL, '바밤바','서울'); -- 들어갔는지 확인 SELECT * FROM DEPT;
DECODE
함수로 감싸서 사용합니다.-- EMP 테이블에서 JOB 별로 SAL의 평균을 조회해보자. -- 기존 GROUP BY SELECT JOB, AVG(SAL) FROM EMP GROUP BY JOB; -- 이번엔 ROLLUP , NULL로 나온다 마지막은 SELECT JOB, AVG(SAL) 급여평균 FROM EMP GROUP BY ROLLUP(JOB); -- ORACLE은 IFNULL이 아니다. NVL(A,DEFAULT) SELECT NVL(JOB, '전체') JOB , AVG(SAL) 급여평균 FROM EMP GROUP BY ROLLUP(JOB);
-- DEPTNO별로 SAL의 합계를 조회해보자. SELECT NVL(DEPTNO, '전체') DEPTNO , SUM(SAL) 급여합계 FROM EMP GROUP BY ROLLUP(DEPTNO);
SQL Error [1722][42000]: ORA-01722: invalid number
숫자 컬럼이라 그냥은 안된다.
-- DECODE 값이 NULL이면 전체 그렇지 않으면 DEPTNO를 변환해서 조회 SELECT DECODE(DEPTNO,NULL, '전체', DEPTNO) DEPTNO , SUM(SAL) 급여합계 FROM EMP GROUP BY ROLLUP(DEPTNO);
-- 묶어서 처리하기도 좋다. - 전체 합계도 나옴 SELECT DEPTNO, JOB, SUM(SAL) 급여합계 FROM EMP GROUP BY ROLLUP(DEPTNO, JOB) ORDER BY DEPTNO; -- -- 이렇게도 가능하다, 전체 합계가 빠짐 SELECT DEPTNO, JOB, SUM(SAL) 급여합계 FROM EMP GROUP BY DEPTNO, ROLLUP(JOB) ORDER BY DEPTNO;
-- CUBE를 써보자. SELECT DEPTNO, JOB, SUM(SAL) 급여합계 FROM EMP GROUP BY CUBE(DEPTNO, JOB) ORDER BY DEPTNO;
이렇게 작성을 했더니, 직업별로도 집계를 해줬다.
CUBE가 ROLLUP보다 많이 사용된다.
-- GROUPING : 중간 집계면 1 아니면 0 SELECT DEPTNO, GROUPING(DEPTNO), JOB, GROUPING(JOB), SUM(SAL) 급여합계 FROM EMP GROUP BY ROLLUP(DEPTNO,JOB); -- -- GROUPING : 중간 집계면 1 아니면 0, 활용해보기 -- 타이틀을 만들려고 하는 거에요 주로 SELECT DEPTNO, DECODE(GROUPING(DEPTNO),1,'전체합계') AS ALLTOT, JOB, DECODE(GROUPING(JOB),1,'부서합계') AS DEPTTOT, SUM(SAL) 급여합계 FROM EMP GROUP BY CUBE(DEPTNO,JOB) ORDER BY DEPTNO;
-- GROUPING SET : 각 컬럼 별 집계를 보자. -- ROLLUP과 비교해보기 SELECT DEPTNO, JOB, SUM(SAL) 급여합계 FROM EMP GROUP BY ROLLUP(DEPTNO, JOB); -- 이렇게 ROLLUP하면 부서 번호별로만 한다. -- GROUPING SET SELECT DEPTNO, JOB, SUM(SAL) 급여합계 FROM EMP GROUP BY GROUPING SETS(DEPTNO, JOB);
GROUPING SETS는 넣어놓은 컬럼 별로 집계를 해서 보여줍니다.
ROLLUP은 앞에 넣은 컬럼에 맞춰 그룹화 해서 집계를 전체적으로 보여줌
SELECT WINDOW_FUNCTION(매개변수) OVER(PARTITION BY 그룹화할 컬럼 이름 ORDER BY WINDOWING FROM 테이블 이름;
-- EMP 테이블에서 전체 SAL에서 자신의 SAL의 비율을 알고 싶다. SELECT ENAME, SAL FROM EMP; -- 왜 오류야? SELECT ENAME, SAL, SAL*100/SUM(SAL) OVER() FROM EMP; -- SUM(SAL)은 1개 , SAL 은 여러개 -- SELECT에 쓰여진 애들은 CARDINALITY가 같아야 한다.
SUM(SAL)을 전부 복사해서 14개의 행으로 만들어서 조회하기
ROWS BETWEEN 시작위치 AND 종료위치
RANGE BETWEEN 시작위치 AND 종료위치
START UNBOUNDED PRECEDING -- 처음 부터 CURRENT ROW -- 현재 행 부터 N PRECENDING -- N 번째 행 앞부터
END UNBOUNDED FOLLOWING -- 마지막까지 CURRENT ROW -- 현재 행 까지 N FOLLLOWING -- N 번째 행까지
-- EMP 테이블에서 EMPNO, ENAME, SAL, 현재행까지의 SAL 합계를 조회 -- OVER 는 14개 다 맞추는거임 SELECT EMPNO, ENAME, SAL, SUM(SAL) OVER(ORDER BY SAL ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW) AS "현재 까지 누적 SAL 값" FROM EMP; -- -- EMP 테이블에서 EMPNO, ENAME, SAL, 현재행부터 마지막 행까지의 SAL 합계를 조회 -- OVER 는 14개 다 맞추는거임 SELECT EMPNO, ENAME, SAL, SUM(SAL) OVER(ORDER BY SAL ROWS BETWEEN CURRENT ROW AND UNBOUNDED FOLLOWING) AS "현재 까지 누적 SAL 값" FROM EMP;
SQLD에서는 별칭 없이 쭉 쓰면 된다. 이거 외워서 써야 한다.
PARTITION BY 컬럼이름
을 기재하면 그룹화해서 집계를 수행한다.부서별 급여 평균을 구해보자.
-- 부서별 급여 평균을 구해보자. SELECT EMPNO, ENAME, SAL, ROUND(AVG(SAL) OVER(PARTITION BY DEPTNO),2) "부서별 급여 평균" FROM EMP;
ROW_NUMBER()
DENSE_RANK()
RANK()
-- 부서별 급여 순위 SELECT DEPTNO,ENAME, SAL, RANK() OVER(PARTITION BY DEPTNO ORDER BY SAL DESC) "RANK급여 순위", DENSE_RANK() OVER(PARTITION BY DEPTNO ORDER BY SAL DESC) "DENSE급여 순위", ROW_NUMBER () OVER(PARTITION BY DEPTNO ORDER BY SAL DESC) " RM급여 순위" FROM EMP;
SELECT 필드목록 FROM 테이블 PIVOT(집계함수 FOR 컬럼이름 IN(컬럼 값 나열) ); 별명
-- PIVOT SELECT JOB, DEPTNO, SAL FROM EMP PIVOT(MAX(SAL) FOR DEPTNO IN(10,20,30);
MERN중 M : mongoDB를 알아보자.
CQRS 중요한데...
왜써?
-> js로 모든것을 다해보자구
Docker
l 이미지 다운로드: docker pull mongo
l 컨테이너 실행: docker run --name 컨테이너이름 -v ~/data:/data/db -d -
p 27017:27017 mongo
u -v ~/data:/data/db는 호스트(컨테이너를 구동하는 로컬 컴퓨터)의 ~/data
디렉터리와 컨테이너의 /data/db 디렉터리를 마운트시키는 옵션으로 이처럼
볼륨을 설정하지 않으면 컨테이너를 삭제할 때 컨테이너에 저장되어 있는
데이터도 삭제되기 때문에 복구할 수 없음
l bash shell 접속: docker exec -it mongodb-container bash
primitive 타입
객체
- {"key":value,"key":value,...}
- key는 중복될 수 없다.
- key의 순서도 기억한다.
- {"name":"mino","job":"student"}
와 {"job":"student","name":"mino"}
는 다른 데이터 입니다.
- key에 공백을 포함할 수 없습니다.
- .
과 $
도 key에 포함할 수 없습니다.
- key는 _
로 시작하지 않습니다.(관례, 예약어가 _
로 시작하기 때문)
- key는 대소문자 구분합니다.
배열
- [데이터 나열]
Mongo DB에서는 하나의 데이터를 Document라고 합니다.
Mongo DB는 데이터의 모임을 collection으로 관리하는데, 스키마가 없기 때문에 하나의 collection에 어떠한 종류의 데이터라도 삽입이 가능합니다.
show dbs
use db이름
db
db.dropDatabase()
Mongo DB는 기본적으로 계정과 비밀번호가 없습니다.
cd bin
mongosh
show dbs
use mino
switched to db mino
라고 나온다.db
show dbs
하면 mino는 안보인다.db.mycollection.insertOne({Name:1})
show dbs
이러면 mino db가 보일거야.[{id:"!",name:"Lee",pw:"!234"},{boardnum:1,title:"제목",content:"내용"}]
이렇게 막 넣기는 가능하지만 아무도 이렇게 안한다.db.createCollection("이름")
db.getCollectionNames()
show collections
db.이름.drop()
db.이름.renameCollection(새로운 이름)
db.createCollection(이름,{capped:true, size:크기})
// collection 생성 db.createCollection('cappedCollection',{capped:true,size:10000}) // 데이터 1개 삽입 db.cappedCollection.insertOne({x:1}) // 데이터 확인 db.cappedCollection.find() // 많은 양의 데이터 삽입 for(i=0;i<1000;i++){ db.cappedCollection.insertOne({x:i}) } // 데이터 확인, 1000개를 넣었는데 어림도 없다. db.cappedCollection.find()
- 데이터를 1000개를 삽입하면 647번부터 데이터가 존재합니다.
- 용량이 초과되어서 이전에 저장된 데이터를 삭제하기 때문입니다.
- 한정된 공간을 사용하는 시스템(IoT와 Embedded System)에서는 새로운 데이터를 저장하기 위해서 과거의 데이터를 지우면서 저장합니다.
_id
라는 속성에 값을 설정하지 않으면, Mongo DB가 _id
라는 속성을 만들어서 값을 대입합니다.db.컬렉션이름.insert(객체)
_id
를 사용하면 에러를 발생db.컬렉션이름.save(객체)
_id
를 사용하면 수정합니다.db.컬렉션이름.insertOne(객체)
db.컬렉션이름.insertMany(객체)
좋은 글 감사합니다!