SELECT department_id , SUM(salary) FROM employees GROUPBY department_id ORDERBY department_id;
HAVING
GROUP BY절 다음에 위치해 GROUP BY한 결과를 대상으로 다시 필터를 거는 역할을 수행.
HAVING 필터 조건 형태로 사용한다.
1 2 3 4 5 6 7 8 9
SELECT period , region , SUM(loan_jan_amt) totl_jan FROM kor_loan_status WHEREperiod='201311' GROUPBYperiod, region HAVINGSUM(loan_jan_amt) >100000 ORDERBY region;
ROLLUP
ROLLUP(expr1, expr2, …)
ROLLUP은 expr로 명시한 표현식을 기준으로 집계한 결과, 즉 추가적인 집계 정보를 보여 준다.
ROLLUP 절에 명시할 수 있는 표현식에는 그룹핑 대상, 즉 SELECT 리스트에서 집계 함수를 제외한 컬럼 등의 표현식이 올 수 있다.
명시한 표현식 수와 순서(오른쪽에서 왼쪽 순으로)에 따라 레벨 별로 집계한 결과가 반환된다.
표현식 개수가 n개이면 n+1 레벨까지, 하위 레벨에서 상위 레벨 순으로 데이터가 집계된다.
1 2 3 4 5 6 7 8 9
-- 2013년 1개월 총 잔액만 구한다. -- ROLLUP : 소그룹간의 합계를 계산함 SELECT period , gubun , SUM(loan_jan_amt) totl_jan FROM kor_loan_status WHEREperiodLIKE'2013%' GROUPBYROLLUP(period, gubun);
CUBE
CUBE(expr1, expr2, …)
ROLLUP과 CUBE는 GROUP BY절에서 사용되어 그룹별 소계를 추가로 보여 주는 역할을 한다.
ROLLUP이 레벨별로 순차적 집계를 했다면, CUBE는 명시한 표현식 개수에 따라 가능한 모든 조합별로 집계한 결과를 반환한다.
CUBE는 2의(expr 수)제곱 만큼 종류별로 집계 된다.
예를 들어, expr 수가 3이면, 집계 결과의 유형은 총 2^3 = 8개가 된다.
1 2 3 4 5 6 7 8
-- CUBE SELECT period , gubun , SUM(loan_jan_amt) totl_jan FROM kor_loan_status WHEREperiodLIKE'2013%' GROUPBYCUBE(period, gubun);
GROUPING SETS
GROUPING SETS (expr1, expr2, expr3)
ROLLUP이나 CUBE처럼 GROUP BY 절에 명시해서 그룹 쿼리에 사용되는 절이다.
GROUP BY 절에 명시했을 때, 괄호 안에 있는 세 표현식별로 각각 집계가 이루어진다.
그러므로 쿼리 형태는 다음과 같다.
((GROUP BY expr1) UNION ALL (GROUP BY expr2) UNION ALL (GROUP BY expr3))
1 2 3 4 5 6 7 8 9
-- GROUPing SETS -- 특정항목에 대한 소계를 계산하는 함수 SELECT period , gubun , SUM(loan_jan_amt) totall FROM kor_loan_status WHEREperiodLIKE'2013%' GROUPBYGROUPING SETS(period, gubun);
-- UNION -- 합집합을 의미한다. -- 두 개의 데이터 집합에서 출발 SELECT goods FROM exp_goods_asia WHERE country ='한국' ORDERBY seq;
SELECT goods FROM exp_goods_asia WHERE country ='일본' ORDERBY seq;
SELECT goods FROM exp_goods_asia WHERE country ='한국' UNION-- 합집합 개념 적용 SELECT goods FROM exp_goods_asia WHERE country ='일본';
중복된 항목 5개를 제외한 15개가 출력되었다.
UNION ALL
UNION ALL은 UNION과 비슷한데 한 가지 다른 것은 중복된 항목도 모두 조회된다는 점이다.
1 2 3 4 5 6 7 8 9
-- UNION ALL
SELECT goods FROM exp_goods_asia WHERE country ='한국' UNIONALL-- 합집합 개념 적용 SELECT goods FROM exp_goods_asia WHERE country ='일본';
중복까지 포함하여 20개의 행의 출력되었다.
INTERSECT
INTERSECT는 합집합이 아닌 교집합을 의미한다.
즉 데이터 집합에서 공통된 항목만 추출해 낸다.
1 2 3 4 5 6 7 8 9
-- INTERSECT -- 합집합이 아니라 교집합을 의미한다. SELECT goods FROM exp_goods_asia WHERE country ='한국' INTERSECT-- 교집합 개념 적용 SELECT goods FROM exp_goods_asia WHERE country ='일본';
MINUS
MINUS는 차집합을 의미한다.
즉 한 데이터 집합을 기준으로 다른 데이터 집합과 공통된 항목을 제외한 결과만 추출해 낸다.
1 2 3 4 5 6 7 8 9
-- MINUS -- 차집합을 의미한다. SELECT goods FROM exp_goods_asia WHERE country ='한국' MINUS -- 차집합 개념 적용 SELECT goods FROM exp_goods_asia WHERE country ='일본';
-- 정리 -- 테이블 생성 : CREATE -- 테이블 변경 (컬럼명, 데이터타입 등) : ALTER -- 테이블 삭제 : DROP
-- 쿼리 -- SELECT (조회) FROM WHERE ORDER BY (...) -- MERGE -- 테이블 데이터 변경 : UPDATE SET -- 테이블 특정 데이터 삭제 : DELETE
-- 연산자 DESC employees;
SELECT employee_id ||'-'|| emp_name AS employee_info FROM employees;
표현식
표현식이란 한 개 이상의 값과 연산자, SQL 함수 등이 결합된 식이다.
조건문은 다음과 같이 사용한다.
CASE WHEN 조건 THEN ELSE END
1 2 3 4 5 6 7 8 9 10
-- 표현식 (조건문) -- CASE WHEN 조건 THEN ELSE END SELECT employee_id , salary , CASEWHEN salary <=5000THEN'C등급' WHEN salary >5000AND salary <=15000THEN'B등급' ELSE'A등급' ENDAS salary_grade FROM employees;
조건식
조간 혹은 조건식은 한 개 이상의 표현식과 논리 연산자가 결합된 식으로 TRUE, FALSE, UNKNOWN 세 가지 타입을 반환한다.
지금까지 SQL문을 학습하면서 WHERE절에서 사용했던 모든 조건이 바로 조건식에 포함된다.
비교 조건식
비교 조건식 : ANY, SOME, ALL 키워드로 비교하는 조건식
ANY
ANY - OR 조건식을 사용해본다.
1 2 3 4 5 6 7 8
-- p.114 -- 비교 조건식 : ANY, SOME, ALL 키워드로 비교하는 조건식 -- ANY - OR SELECT employee_id , salary FROM employees WHERE salary =2000or salary =3000or salary =4000
ANY가 ‘아무것’이나 ‘하나’라는 뜻이 있으므로 위 코드는 salary(급여)가 2000이나 3000이나 4000 중 하나라도 일치하는 모든 사원을 추출한 것이다.
하나라도 일치하면 추출하는 것이므로 ANY는 OR로 표현이 가능하다.
ALL
ALL 조건문을 사용해본다.
ALL이므로 모든 조건을 만족하는 것만 추출한다.
ALL 조건식은 AND 조건으로 변환할 수 있다.
1 2 3 4 5 6 7 8
-- ALL -- 모든 조건을 동시에 만족해야 함 SELECT employee_id , salary FROM employees WHERE salary =ALL(2000, 3000, 4000) ORDERBY employee_id;
SOME
SOME 조건문을 사용한다.
SOME은 ANY와 동일하게 사용되며 동작한다.
1 2 3 4 5 6 7
-- SOME SELECT employee_id , salary FROM employees WHERE salary =SOME(2000, 3000, 4000) ORDERBY employee_id;
논리 조건식
논리 조건식 = 조건절에서 AND, OR, NOT을 사용하는 조건식
AND는 모든 조건을 만족해야 하고 OR는 여러 조건 중 하나만 만족해도 TRUE를 반환된다.
NOT은 조건식 평가 결과가 **거짓(FALSE)**일 때 원하는 결과, 즉 TRUE를 반환한다.
NOT을 사용해본다.
1 2 3 4 5 6 7
-- 논리 조건식 SELECT employee_id , salary FROM employees WHERENOT (salary >=2500) ORDERBY employee_id;
BETWEEN AND 조건식
BETWEEN은 범위에 해당되는 값을 찾을 때 사용하는데 크거나 같고 작거나 같은 값을 찾는다.
따라서 ‘>=’와 ‘<=’ 논리 연산자로 변환이 가능하다.
1 2 3 4 5 6 7 8 9
-- BETWEEN AND 조건식 -- 범위 지정 -- 급여가 2000~2500 사이에 해당하는 사원을 조회하라 SELECT employee_id , salary FROM employees WHERE salary BETWEEN2000AND2500 ORDERBY employee_id;
IN 조건식
OR, ANY와 같은 기능을 수행 가능하다.
IN 조건식은 조건절에 명시한 값이 포함된 건을 반환하는데 앞에서 배웠던 ANY와 비슷하다.
1 2 3 4 5 6 7 8
-- IN 조건식 -- OR - ANY 조건식과 비슷하다 SELECT employee_id , salary FROM employees WHERE salary IN (2000, 3000, 4000) ORDERBY employee_id;
NOT IN 조건식
IN 조건식과 반대의 결과를 출력한다.
1 2 3 4 5 6 7
-- NOT IN SELECT employee_id , salary FROM employees WHERE salary NOTIN (2000, 3000, 4000) ORDERBY employee_id;
EXISTS 조건식
XISTS 조건식 역시 IN과 비슷하지만 후행 조건절로 값의 리스트가 아닌 서브 쿼리만 올 수 있다.
또한 서브 쿼리 내에서 조인 조건(a.department_id = b.department_id)이 있어야 한다.
1 2 3 4 5 6 7 8 9 10
-- EXISTS 조건식 -- IN과 비슷함, 단 서브쿼리 절에만 사용 가능 SELECT department_id , department_name FROM departments a WHEREEXISTS ( SELECT* FROM employees b WHERE a.department_id = b.department_id AND b.salary >3000) ORDERBY a.department_name;
서브쿼리 부분이 메인이다.
LIKE 조건식
LIKE 조건식은 문자열의 패턴을 검색할 때 사용하는 조건식이다.
예를 들어, 사원 테이블에서 사원이름이 ‘A’로 시작되는 사원을 조회하는 쿼리를 작성한다면 다음과 같이 LIKE 조건식을 사용.
1 2 3 4 5 6 7
-- LIKE 조건식 -- 문자열의 패턴을 검색할 때 사용하는 조건식 -- 사원 테이블 사원 이름이 'A'로 시작되는 사원 조회 SELECT emp_name FROM employees WHERE emp_name LIKE'A%' ORDERBY emp_name;
-- p.98 CREATETABLE ex3_2( emp_id NUMBER , emp_name VARCHAR2(100) );
-- 실무에서 많이 쓰임 INSERTINTO ex3_2(emp_id, emp_name) SELECT employee_id , emp_name FROM employees WHERE salary >5000;
SELECT*FROM ex3_2;
UPDATE 문 사용법
UPDATE : 기존 데이터를 수정
ARTER : 기존 테이블의 컬럼명 수정, 제약조건
1 2 3
UPDATE 테이블명 SET 컬럼1= 변경값1, 컬럼2= 변경값2 WHERE 조건;
UPDATE 문
UPDATE 문을 실제로 사용해보자.
1 2 3 4 5 6 7
SELECT*FROM ex3_1;
-- col2 모두 50으로 변경한다. UPDATE ex3_1 SET col2 =50;
SELECT*FROM ex3_1;
col2 값이 모두 50으로 수정되었다.
SELECT문으로 사람 이름을 수정해보자.
1 2 3 4 5
UPDATE ex3_2 SET EMP_NAME =10-- Michael Hartstein WHERE EMP_ID =201;
SELECT*FROM ex3_2;
Michael이란 이름이 10으로 변경되었다.
MERGE
조건 비교해서 테이블에 해당 조건에 맞는 데이터가 없으면 INSERT 있으면 UPDATE하는 방식이다.
1 2 3 4 5 6 7 8 9 10
MERGE INTO [스키마.]테이블명 USING (update나 insert될 데이터 원천) ON (update될 조건) WHEN MATCHED THEN SET 컬럼1 = 값1, 컬럼2 = 값2, ... WHERE update 조건 DELETE WHERE update_delete 조건 WHEN NOT MATCHED THEN INSERT (컬럼1, 컬럼2, ...) VALUES (값1, 값2,...) WHERE insert 조건;
-- MERGE -- 조건 비교해서 테이블에 해당 조건에 맞는 데이터가 없으면 INSERT -- 있으면 UPDATE
CREATETABLE ex3_3( employee_id NUMBER , bonum_amt NUMBER DEFAULT0 );
SELECT*FROM SALES; DESC SALES;
-- ex3_3 신규테이블 생성 INSERTINTO ex3_3(employee_id) SELECT e.employee_id FROM employees e, sales s WHERE e.employee_id = s.employee_id AND s.SALES_MONTH BETWEEN'200010'AND'200012' GROUPBY e.employee_id; -- group by를 통해 중복 제거
SELECT*FROM ex3_3 ORDERBY employee_id;
서브쿼리
쿼리 안에 또 다른 쿼리가 있는 형태이다.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
-- (1) 관리자 사번(manager_id)이 146번인 사원을 찾는다. -- (2) ex3_3 테이블에 있는 사원의 사번과 일치하면 -- 보너스 금액에 자신의 급여의 1%를 보너스로 갱신 -- (3) ex3_3 테이블에 있는 사원의 사번과 일치하지 않으면 -- (1)의 결과의 사원을 신규로 입력 (이 때 보너스 금액은 급여의 0.1% -- (4) 이 때 급여가 8000미만인 사원만 처리해보자.
-- 서브쿼리 SELECT employee_id , manager_id , salary , salary *0.01-- 10% FROM employees WHERE employee_id IN (SELECT employee_id FROM ex3_3);
서브쿼리의 또 다른 예시이다.
1 2 3 4 5 6 7 8 9 10 11
-- 관리자 사번이 146번인 사원은 161번 사원 한 명이므로 -- ex3_3 테이블에서 161인 건의 보너스 금액은 7,000 * 0.01, 즉 70으로 갱신
SELECT employee_id , manager_id , salary , salary *0.01-- 10% FROM employees WHERE employee_id NOTIN (SELECT employee_id FROM ex3_3) AND manager_id =146;
MERGE 문
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
MERGEINTO ex3_3 d USING (SELECT employee_id , salary , manager_id FROM employees WHERE manager_id =146) b ON (d.employee_id = b.employee_id) WHEN MATCHED THEN UPDATESET d.bonus_amt = d.bonus_amt + b.salary *0.01 WHENNOT MATCHED THEN INSERT (d.employee_id, d.bonus_amt) VALUES (b.employee_id, b.salary *0.001) WHERE (b.salary <8000); SELECT*FROM ex3_3 ORDERBY employee_id;
오타 처리하다 3번 실행한 결과이다.
DELETE 문
UPDATE에 비해 간단하다.
삭제하기만 하면 되기 때문.
1 2 3 4
-- DELETE 문 -- 106p DELETE ex3_3; SELECT*FROM ex3_3;
COMMIT, ROLLBACK
commit과 rollback을 사용해보자.
1 2 3 4 5 6 7 8 9 10 11 12 13
-- Commit Rollback Truncate -- Commit : 변경한 데이터를 DB에 마지막으로 반영 -- ROLLBACK : 반대로 변경한 데이터를 변경하기 이전 상태로 되돌림 CREATETABLE ex3_4 ( employee_id NUMBER ); INSERTINTO ex3_4 VALUES (100);
SELECT*FROM ex3_4;
commit; rollback;
commit 후에는, sqlplus에서도 테이블을 출력 할 수 있게 된다.
TRUNCATE문
한번 실행 시, 데이터 바로 삭제한다.
ROLLBACK 적용 안됨
1 2 3 4 5 6
-- TRUNCATE 문 -- 한번 실행시, 데이터 바로 삭제, ROLLBACK 적용 안됨 -- DELETE문은 데이터 삭제 후, COMMIT 필요 / ROLLBACK 데이터가 삭제되기 전의 복구 불가
SELECT constraint_name, constraint_type, table_name, search_condition FROM user_constraints WHERE table_name ='EX2_8'; INSERTINTO ex2_8 VALUES('','AA'); -- 오류 보고 ORA-01400: NULL을 ("ORA_USER"."EX2_8"."COL") 안에 삽입할 수 없습니다 -- NULL 값을 삽입하여 생기는 오류이다. NULL값 대신 다른 값을 입력하자.
여기까지 입력하고 실행하면 오류가 발생한다.
— 오류 보고 ORA-01400: NULL을 (“ORA_USER”.”EX2_8”.”COL”) 안에 삽입할 수 없습니다
NULL 값을 삽입하여 생기는 오류이다. NULL값 대신 다른 값을 입력하자.
1 2 3 4
-- 오류 보고 ORA-01400: NULL을 ("ORA_USER"."EX2_8"."COL") 안에 삽입할 수 없습니다 -- NULL 값을 삽입하여 생기는 오류이다. NULL값 대신 다른 값을 입력하자. INSERTINTO ex2_8 VALUES('AA','AA'); SELECT*FROM ex2_8;
이번에는 오류가 출력되지 않았다.
같은 값을 다시 입력해보자.
1 2 3 4
INSERTINTO ex2_8 VALUES('AA','AA'); -- ORA-00001: 무결성 제약 조건(ORA_USER.SYS_C007484)에 위배됩니다 -- 값이 같은 데이터를 입력하여 생기는 오류이다. 다른 데이터를 입력해야 한다.
-- 제약조건 추가 ALTERTABLE ex2_10 ADDCONSTRAINTS pk_ex2_10 PRIMARY KEY (col11);
-- USER CONSTRAINTS 제약 조건 확인 SELECT constraint_name, constraint_type, table_name, search_condition FROM user_constraints WHERE table_name ='EX2_10';
제약조건이 추가되었다.
제약조건을 삭제해보자.
1 2 3 4 5 6 7
-- 제약조건 삭제 ALTERTABLE ex2_10 DROP CONSTRAINTS pk_ex2_10; -- USER CONSTRAINTS 제약 조건 확인 SELECT constraint_name, constraint_type, table_name, search_condition FROM user_constraints WHERE table_name ='EX2_10';
SELECT a.employee_id , a.emp_name , a.department_id -- 부서명 컬럼 , b.department_name FROM employees a , departments b WHERE a.department_id = b.department_id;
CREATEOR REPLACE VIEW emp_dept_v1 AS SELECT a.employee_id , a.emp_name , a.department_id , b.department_name FROM employees a , departments b WHERE a.department_id = b.department_id;
새로운 view가 생성된다.
인덱스(index)
인덱스를 생성한다.
1 2 3 4 5 6 7 8 9 10 11 12 13 14
-- 인덱스 생성 -- 75p -- 추후 공부해야 할 내용 : 인텍스 내부 구조에 따른 분류 ---- (초중급 레벨) B-Tree 인덱스, 비트맵 인덱스, 함수 기반 인덱스 ---- DB 성능 -- 인덱스 생성 -- col11 값에 중복 값을 허용하지 않는다. -- 인덱스 생성 시, user_indexes 시스템 뷰에서 내역 확인 CREATEUNIQUE INDEX ex2_10_ix011 ON ex2_10(col11);
SELECT index_name, index_type, table_name, uniqueness FROM user_indexes WHERE table_name ='EX2_10';
f = open('fromdb.csv', 'r') f.read() print("reading data is done!")
→ 저장 후 실행
→ python3 createrecord.py
새 폴더 생성
→ 폴더 생성 : vi querydf.py
→ 내용 작성
import psycopg2 as db import pandas as pd conn_string="dbname='dataengineering' host='localhost' user='postgres' password='postgres'" conn=db.connect(conn_string)
df = pd.read_sql("select * from users", conn) print(df.head())
import psycopg2 as db from faker import Faker fake=Faker() data=[] i=2 for r in range(1000): data.append((i,fake.name(),fake.street_address(), fake.city(),fake.zipcode())) i+=1 data_for_db=tuple(data) print(data_for_db) conn_string="dbname='dataengineering' host='localhost' user='postgres' password='postgres'" # 집pc의 경우에는 password='201610974'
conn=db.connect(conn_string) cur=conn.cursor() query = "insert into users (id,name,street,city,zip) values(%s,%s,%s,%s,%s)" print(cur.mogrify(query,data_for_db[1])) cur.executemany(query,data_for_db) conn.commit() query2 = "select * from users"