-- select 구문은 트랜잭션과 아무런 연관성이 없음 -- 데이터의 변화와 상관이 없기 때문이다. select * from DEPT; -- DEPT 테이블에 데이터를 하나 삽입해보자. -- dept 테이블에 데이터 1개 삽입, 이전 트랜잭션이 없어서 트랜잭션 생성 insert into DEPT (deptno, dname, loc) values (50, "Computing", "SEOUL"); select * from DEPT; -- 철회: savepoint를 입력하지 않으면 트랜잭션 시작 전으로 복구 ROLLBACK; -- 내가 insert 한 것이 없어졌어! -- 트랜잭션 전으로 돌아가버렸다. select * from DEPT;
insert 명령을 수행한 데이터가 없어졌다. COMMIT을 안했기 때문이다.
-- 다시 데이터를 넣어보자. -- 트랜잭션이 다시 하나 생성된다. insert into DEPT (deptno, dname, loc) values (50, "Computing", "SEOUL"); -- 이제 create 구문을 하나 써볼까? -- DEPT 복제 테이블 하나 생성하기 create table DEPT_COPY as select * from DEPT; -- 다시 ROLLBACK하기 ROLLBACK; -- 이번에는 50이 나온다. -- ROLLBACK을 했는데 왜 나왔지? -- DDL(create, drop, alter, truncate, rename)이나 -- DCL(grant, revoke)를 수행하면 AUTO COMMIT이다. -- why? : 관리자 영역의 명령어들이라 나중에 적용되면 안되기 때문이다. -- 트랜잭션은 변경 내역을 반영하고 종료를 한다. -- 물론 create한 테이블도 잘 보인다. select * from DEPT; select * from DEPT_COPY;
-- 트랜잭션 생성 insert into DEPT (deptno, dname, loc) values (60, "Computing1", "SEOUL1"); savepoint sv1; insert into DEPT (deptno, dname, loc) values (70, "Computing2", "SEOUL2"); savepoint sv2; insert into DEPT (deptno, dname, loc) values (80, "Computing3", "SEOUL3"); select * from DEPT; -- sv1을 생성한 지점으로 이동 ROLLBACK TO sv1; -- sv1으로 오게 된다면 sv2는 없는 것을 생각하자. select * from DEPT; -- 이대로 냅두면 lock이 걸린다. -- 왜냐면 내가 rollback이나 commit, ddel, dcl 한 적이 없음 -- 에러는 아니고 데드락에 걸려요 이걸 connect timeout을 걸어야 함 -- commit 수행 : 트랜잭션 종료 COMMIT;
SELECT * from ? ;
이 명령은 보조기억장치에 두고 실행한다. 이 명령을 실행하면 메모리에 올려서 cpu에서 작업하는것이다.select ~ from (select 구문) 이름
slsect * from EMP, DEPT where EMP.DEPTNO=DEPT.DEPTNO and JOB='CLERK';
select * from (select * from EMP where JOB='CLERK') TEMP, DEPT where TEMP.DEPTNO=DEPT.DEPTNO;
create [or replace] view 뷰이름 as select 구문 [with check option] [with read only]
MySQL은 버전에 따라서 OR REPLACE를 사용하지 못하는 경우가 있다.
WITH CHECK OPTION
WITH READ ONLY
NOT NULL
컬럼을 제외하고 만든 경우에는 DML 작업이 안됩니다.READ ONLY
옵션을 추가해야 합니다.ALTER
를 사용할 수 없습니다.DROP VIEW 뷰이름;
-- emp 테이블에서 empno, ename, sal, comm만으로 구성된 뷰를 생성 create view KIM as select EMPNO, ENAME, SAL, COMM from EMP; -- 사용은 테이블과 똑같다. select * from KIM; -- VIEW에 DML(삽입 삭제, 갱신) 작업은 가능한 경우도 있고 -- 가능하지 않는 경우도 존재 DESC EMP; -- view에 데이터 삽입 insert into KIM(EMPNO, ENAME, SAL, COMM) VALUES(999, 'MINO', 10000, 9000); SELECT * FROM KIM; -- 확인해 보면 EMP 테이블에 들어가있음 SELECT * FROM EMP; -- VIEW 구조 확인 DESC KIM; -- VIEW 삭제 DROP VIEW KIM;
create temporary table 테이블이름(내용);
-- 임시 테이블 create temporary table temp( name char(20) ); select * from temp;
해당 세션을 종료하고 새 세션을 킨다면 사용 못하는 임시 테이블이다.
WITH 테이블이름(컬럼이름 나열) AS (SELECT 구문)
SELECT 구문이 복잡한 경우, 동일한 SELECT 구문 여러 번 입력해야 하는 경우가 있는데, 이 때 CTE를 사용하면 편리하다.
2개 이상의 CTE를 사용하고자 하는 경우에는 콤마(,)로 구분
-- CTE : SQL 수행 중에만 일시적으로 -- 메모리 공간을 할당받아서 사용하는 테이블 -- FROM 절에 쓰는 것 : INLINE VIEW -- SUB QUERY는WHERE 뒤에 있는거 SELECT * FROM (SELECT NAME, SALARY, SCORE) FROM tStaff WHERE DEPART='영업부' AND GENDER='남') TEMP WHERE SALARY>=(SELECT AVG(SALARY) FROM TEMP); -- 이러면 WEHRE에 있는 TEMP가 뭔지 모른다. -- 이와 유사한 작업을 INLINE VIEW에서 가능할거라 보이지만, -- INLINE VIEW는 SUB QUERY보다 늦게 수행되기 때문에 -- INLINEEVESMS SUB QUERY에서 못쓴다. WITH TEMP AS (SELECT NAME, SALARY, SCORE FROM tStaff WHERE DEPART='영업부'AND GENDER='남') SELECT * FROM TEMP WHERE SALARY>=(SELECT AVG(SALARY)FROM TEMP);
DELIMITER 기호기호 CREATE [OR REPLACE] 프로시저 이름() BEGIN SQL 작성 END 기호기호 DELIMITER
CALL 프로시저이름(매개변수 나열)
-- 프로시저 생성 -- delimiter는 프로시저 종료를 알리기 위한 기호설정 -- 왜냐하면 안에 이미 세미콜론이 있기 때문에 모르기 때문이다. -- 두개로 쓰는 이유는 하나로 만들면 데이터로 사용되는 것과 -- 혼동이 올 수 있기 때문이다. -- dbeaver에서 수행할 때는 sql script 실행으로 실행해야 한다. delimiter // create procedure myproc(vuserid char(15), vname varchar(20), vbirthyear int(11), vaddr char(100), vmobile char(11), vmdate date) begin insert into usertbl values(vuserid, vname, vbirthyear,vaddr, vmobile, vmdate); end// delimiter ; -- 지우기는 drop 입니다. drop procedure myproc; -- 실행하기 call myproc('mino', '이민호', 1998,'서울' , '01012341234', '1998-09-25'); select * from usertbl;
~~~ 하기 전에 ~~한다
는 유효성 검사~~~하고 나서는 ~~한다
는 로깅을 하는 것이다.create trigger 이름 timing [before|after] event [insert|update|delete] on 테이블 이름 [for each row] -- 행단위? 아니면 한번만(한번만이면 생략가능) [where 조건] begin 수행할 내용 end
권한 문제로 트리거 생성이 안되면 관리자 계정으로 접속해서 명령을 수행하거나, 관리자 계정에서
set global log_bin_trust_function_creators=on;
명령어를 입력해주자.
-- 트리거를 수행하기 위한 샘플 테이블 생성 create table emp01( empno int primary key, ename varchar(30) not null, job varchar(100) ); create table sal01( salno int primary key auto_increment, sal float(7,2), empno int references emp01(empno) on delete cascade ); -- emp01 테이블에 데이터 추가시, sal01테이블에 데이터가 자동으로 추가되는 트리거 set global log_bin_trust_function_creators=on; delimiter // create trigger trg_01 after insert on emp01 for each row BEGIN insert into sal01(sal,empno) values(100,NEW.empno); END// delimiter ; insert into emp01 values(1,'mino','데이터분석가'); select * from emp01; select * from sal01;
NEW.컬럼이름
을 사용하면 되고, 수정되기 전의 값이나 삭제되는 값을 사용하고자 하는 경우는 OLD.컬럼이름
을 사용하면 됩니다.
- SQL Mapper
- 소스코드와 SQL을 분리시켜서 수행하는 방식
- MyBatis가 대표적인 Framework(우리나라 SI 업계에서 주로 이용, 쉽기는 하지만 효율이 떨어짐)
pip install pyMySQL
변수 = pymysql.connect(host=?,port=?,user=?,passwd=?,db=?,charset=?)
성공하면 메시지 x 실패하면 에러 메시지와 함께 예외 발생함
변수.close()
: 접속 종료
# 파이썬 MySQL 드라이버 패키지 다운로드 pip install pyMySQL import pymysql try: con=pymysql.connect(host='localhost',port=3306,db='mino', user='root', passwd='12alsgh12!', charset='utf8') print(con) except: print("예외 발생!", sys.exc_info()) finally: if con!=None: con.close()
<과정>
SQL 실행 객체.excute(SQL[,parameter 값 나열])
con.commit()
을 호출하면 원본에 반영됩니다.작업할 테이블 확인 : DBeaver 에서 확인
파이썬에서 SQL 작성
import pymysql import sys try: #db 연결객체 생성 con=pymysql.connect(host='localhost',port=3306,db='mino', user='--', passwd='--', charset='utf8') print(con) #sql 실행 객체 생성 cursor=con.cursor() #sql 실행 - 값을 직접 sql에작성 cursor.execute("insert into DEPT values(11,'비서','서울')") #sql 실행 - sql에 서식을 설정하고, 파라미터를 대입하는 코드 작성 : 권장 cursor.execute("insert into DEPT values(%s,%s,%s)", (12,'기획','제주')) ### 이렇게 하고 dbeaver에서 select * from DEPT 보면 데이터 없음 # 여기의 DEPT와 DBeaver의 DEPT와는 다른 것이다. (세션이 다르다.) # Commit을 해주자. con.commit() except: print("예외 발생!", sys.exc_info()) finally: if con!=None: con.close()
DB 연결객체 생성 시, user 와 pwd는 기존 db와 맞아야 한다.
똑같이 쓰는 부분들이 존재한다. 이는 프레임워크가 채워줄 것이다.
fetchone
메서드를 호출하면 하나의 튜플로 데이터를 리턴합니다.fetchall
메서드를 호출하면, tuple의 tuple로 모든 데이터를 리턴합니다.fetchone
호출 경우fetchall
을 호출함import pymysql import sys try: #db 연결객체 생성 con=pymysql.connect(host='localhost',port=3306, db='mino', user='-', passwd='-', charset='utf8') #sql 실행 객체 생성 cursor=con.cursor() cursor.execute("select * from DEPT where DEPTNO=%s",(12)) #검색 결과 중 하나의 데이터를 읽어오는 것 record=cursor.fetchone() #검색된 결과가 없다면 None, 존재하면 Tuple #print(record) if record==None: print("검색된 데이터가 없음") else: for attr in record: print(attr) except: print("예외 발생!", sys.exc_info()) finally: if con!=None: con.close()
데이터베이스에 파일을 저장하는 방법
- 파일을 파일 서버(AWS의 S3 또는 Google Firebase의 File Storage 서비스) 에 별도로 젖아하고 그 경로를 저장하는 방법
- 파일의 이름과 내용을 모두 데이터베이스에 저장하는 방식
파일을 파일 서버에 별도로 저장하면 DB에 저장하는 것 보다 비용이 저렴하지만 파일을 사용하려고 할 때 마다 다운로드를 받아야 합니다.
- select 구문 만으로는 파일을 사용할 수 없습니다.
최근에는 대부분 파일을 데이터베이스에 저장하지는 않습니다.
파일의 내용을 데이터베이스에 저장하고자 하면, 데이터 타입을 blob or longblob
로 설정해야 합니다.
- 파일의 내용을 저장할 때, 형식을 알아야 하기 때문에 파일 이름을 같이 저장
파이썬에서는 BLOB
는 bytes와 매핑됩니다.
DB에 파일을 저장할 수 있는 테이블을 생성해야 한다.
create table blobtable( filename varchar(100), filecontent longblob ); desc blobtable;
import pymysql import sys try: #db 연결객체 생성 con=pymysql.connect(host='localhost',port=3306, db='mino', user='-', passwd='-', charset='utf8') #sql 실행 객체 생성 cursor=con.cursor() #삽입할 이미지 파일 내용 읽기 f=open('galoo7.jpg','rb') galoo=f.read() f.close() # 데이터 삽입 cursor.execute("insert into blobtable values(%s, %s)", ("galoo7.jpg",galoo)) con.commit() except: print("예외 발생!", sys.exc_info()) finally: if con!=None: con.close()
import pymysql import sys try: #db 연결객체 생성 con=pymysql.connect(host='localhost',port=3306, db='mino', user='--', passwd='--', charset='utf8') #sql 실행 객체 생성 cursor=con.cursor() #데이터 읽어오기 cursor.execute("select * from blobtable") data=cursor.fetchone() #두 번쨰 데이터가 blob 이므로 두번째 데이터를 파일로 변경 print(data[0]) f=open(data[0],'wb') f.write(data[1]) f.close() #select는 transaction이랑 상관 없어서 commit 할 필요가 없음 #con.commit() except: print("예외 발생!", sys.exc_info()) finally: if con!=None: con.close()
몇 번째가 이름이고 몇 번째가 사진인지 데이터 인덱스 잘 생각하기
docker run --name 컨테이너이름 -d -p 포트번호(1521):1521 jaspeen/oracle-xe-11g
이러면 관리자는 sys, system 이고, sid 는 xe가 되고 관리자는 system이고 비번은 oracledocker run --name 컨테이너이름 -d -p 포트번호(1521):1521 -e ORACLE_PASSWORD=관리자비밀번호 gvenzl/oracle-xe
sid는 xe가 되고 관리자는 sys, system이며 비번은 설정한 값
소중한 정보 감사드립니다!