1. 트랜잭션
2. SQL 고급 문법
Atomic하게 실행되어야 하는 SQL들을 묶어서 하나의 작업처럼 처리하는 방법
Atomic(원자성) : 여러 개의 sql이 동시에 성공을 하거나 혹은 동시에 실패를 해야지만 데이터의 정합성에 문제가 없음을 의미
이는 DDL이나 DML 중 레코드를 수정/추가/삭제한 것에만 의미가 있음.
( UPDATE, INSERT, DELETE )
SELECT에는 트랜잭션을 사용할 이유가 없음
BEGIN과 END 혹은 BEGIN과 COMMIT 사이에 해당 SQL들을 사용
ROLLBACK
은행 계좌 이체가 아주 좋은 예시
계좌 이체 : 인출과 입금의 두 과정으로 이루어짐
만일 인출은 성공했는데 입금이 실패한다면?
이 두 과정은 동시에 성공하던지 실패해야함
-> Atomic하다는 의미
이런 과정들을 트랜잭션으로 묶어줘야함
조회만 한다면 이는 트랜잭션으로 묶일 이유가 없음
e.g.)
BEGIN;
A의 계좌로부터 인출; -- a
B의 계좌로 입금; -- b
END; -- END OR COMMIT
이 a와 b 명령어 들은 마치 하나의 명령어처럼 처리된다. 다 성공하던지 다 실패하던지 둘 중의 하나가 됨
END와 COMMIT은 동일
만일 BEGIN 전의 상태로 돌아가고 싶다면 ROLLBACK을 실행
이 동작은 commit mode에 따라 달라짐!
autocommit = TRUEautocommit = FalseGoogle Colab의 트랜잭션
기본적으로 모든 SQL statement가 바로 커밋됨 (autocommit=True)
이를 바꾸고 싶다면 BEGIN;END; 혹은 BEGIN;COMMIT을 사용 (혹은 ROLLBACK;)
psycopg2의 트랜잭션
autocommit이라는 파라미터로 조절가능
autocommit=True가 되면 기본적으로 PostgreSQL의 커밋 모드와 동일
autocommit=False가 되면 커넥션 객체의 .commit()과 .rollback()함수로 트랜잭션 조절 가능
무엇을 사용할지는 개인 취향
e.g.)
Redshift는 autocommit=True가 default이기 때문에 아래 명령어를 실행시 실제 DB에 바로 적재가 된다.
%%sql
DROP TABLE IF EXISTS adhoc.keeyong_name_gender;
CREATE TABLE adhoc.keeyong_name_gender (
name varchar(32),
gender varchar(16)
);
INSERT INTO adhoc.keeyong_name_gender VALUES ('Ben', 'Male'), ('Maddie', 'Female');
DELETE FROM table_name (not DELETE * FROM)
DROP TABLE table_nameTRUNCATE table_name
DELETE FROM은 속도가 느림DELETE FROM은 트랜잭션 내에서 사용 가능,
TRUNCATE은 트랜잭션 안에서 사용하면ROLLBACK이 안됨.
import psycopg2
# Redshift connection 함수
def get_Redshift_connection(autocommit):
host = "redshift연결과 동일한 host"
redshift_user = ""
redshift_pass = ""
port =
dbname = ""
conn = psycopg2.connect("dbname={dbname} user={user} host={host} password={password} port={port}".format(
dbname=dbname,
user=redshift_user,
password=redshift_pass,
host=host,
port=port
))
# 여기서 autocommit을 설정
conn.set_session(autocommit=autocommit)
return conn
# Redshift Connection을 만드는데,
# autocommit=False로 지정
conn = get_Redshift_connection(False)
# Redshift의 커서(입력을 기다리는 object)를 가져옴
cur = conn.cursor()
# 커서로 sql를 지정
cur.execute("SELECT * FROM adhoc.keeyong_name_gender;")
# sql의 결과는 fetchall()로 받을 수 있음
res = cur.fetchall()
for r in res:
print(r)
# autocommit=False일 때의 delete
# 결과는, Redshift에 있는 DB에는 반영이 되지않고 이 세션에서만 적용됨.
cur.execute("DELETE FROM adhoc.keeyong_name_gender;")
# autocommit=False일 때의 insert
# 이 결과도, Redshift에 있는 DB에는 반영이 되지않고 이 세션에서만 적용됨.
cur.execute("INSERT INTO adhoc.keeyong_name_gender VALUES ('Keeyong', 'Male');")
# commit을 했으니 위에서 수행한 명령들이 Redshift의 DB에도 반영됨
cur.execute("COMMIT;")
# 연결 해제
conn.close()
BEGIN;END; 혹은 BEGIN;COMMIT을 사용cur.execute("BEGIN;")
cur.execute("DELETE FROM adhoc.keeyong_name_gender;")
cur.execute("INSERT INTO adhoc.keeyong_name_gender VALUES ('Benjamin', 'Male');")
cur.execute("END;")
-> 명령어 하나가 잘못된 경우, 트랜잭션 내의 모든 명령어가 실행이 되지 않는다.
- UNION, EXCEPT, INTERSECT
- COALESCE, NULLIF
- LISTAGG
- LAG
- WINDOW 함수
- ROW_NUMBER OVER
- SUM OVER
- FIRST_VALUE, LAST_VALUE
- JSON Parsing 함수
UNION (합집합)
EXCEPT (minus)
INTERSECT (교집합)
COALESCE(Expression1, Expression2, ...)
첫번째 Expression부터 값이 NULL이 아닌 것이 나오면 그 값을 리턴하고 모두 NULL인 경우 NULL을 리턴한다.
NULL값을 다른 값으로 바꾸고 싶을 때 사용한다.
NULLIF(Expression1, Expression2, ...)
SELECT
userid,
-- within ... 을 붙이지 않으면 순서가 랜덤하게 리스트가 만들어진다.
LISTAGG(channel) WITHIN GROUP (ORDER BY ts) channels
FROM raw_data.user_session_channel usc
JOIN raw_data.session_timestamp st ON usc.sessionid = st.sessionid
GROUP BY 1
LIMIT 10;
-> ex) 68 YoutubeGoogleInstagramYoutube...
%%sql
SELECT
userid,
-- -> 구분자를 추가
LISTAGG(channel, '->') WITHIN GROUP (ORDER BY ts) channels
FROM raw_data.user_session_channel usc
JOIN raw_data.session_timestamp st ON usc.sessionid = st.sessionid
GROUP BY 1
LIMIT 10;
-> ex) 68 Youtube->Google->Instagram->Youtube->...
Syntax :
function(expression) OVER ([PARTITION BY expression] [ORDER BY expression])Useful_functions:
LAG함수
%%sql
SELECT usc.*, st.ts, LAG(channel, 1) OVER (PARTITION BY userId ORDER BY ts) prev_channel
FROM raw_data.user_session_channel usc
JOIN raw_data.session_timestamp st ON usc.sessionid = st.sessionid
ORDER BY usc.userid, st.ts
LIMIT 100;
%%sql
-- DESC로 순서만 바꿔주면 다음 채널 찾기로 바뀜
SELECT usc.*, st.ts, LAG(channel, 1) OVER (PARTITION BY userId ORDER BY ts DESC) prev_channel
FROM raw_data.user_session_channel usc
JOIN raw_data.session_timestamp st ON usc.sessionid = st.sessionid
ORDER BY usc.userid, st.ts
LIMIT 100;
JSON_EXTRACT_PATH_TEXT%%sql
/*
f2 : {
f3 : 1
}
f4 : {
f5 : 99
f6 : star
}
이렇게 되있을 때,
f4의 f6을 가져오겠다.
즉, star가 반환된다.
*/
SELECT JSON_EXTRACT_PATH_TEXT('{"f2":{"f3": "1"},"f4":{"f5":"99","f6":"star"}}','f4', 'f6');
-> 내가 이미 JSON String의 구조를 알고 있고, 뭐를 읽어야하는 지 알고 있는 경우 매우 유용