문제 https://www.acmicpc.net/problem/1912 1912번: 연속합 첫째 줄에 정수 n(1 ≤ n ≤ 100,000)이 주어지고 둘째 줄에는 n개의 정수로 이루어진 수열이 주어진다. 수는 -1,000보다 크거나 같고, 1,000보다 작거나 같은 정수이다. www.acmicpc.net n개의 정수로 이루어진 임의의 수열이 주어진다. 우리는 이 중 연속된 몇 개의 수를 선택해서 구할 수 있는 합 중 가장 큰 합을 구하려고 한다. 단, 수는 한 개 이상 선택해야 한다. 예를 들어서 10, -4, 3, 1, 5, 6, -35, 12, 21, -1 이라는 수열이 주어졌다고 하자. 여기서 정답은 12+21인 33이 정답이 된다. 입력 첫째 줄에 정수 n(1 ≤ n ≤ 100,000)이 주어지..
문제 https://www.acmicpc.net/problem/1904 1904번: 01타일 지원이에게 2진 수열을 가르쳐 주기 위해, 지원이 아버지는 그에게 타일들을 선물해주셨다. 그리고 이 각각의 타일들은 0 또는 1이 쓰여 있는 낱장의 타일들이다. 어느 날 짓궂은 동주가 지원이 www.acmicpc.net 지원이에게 2진 수열을 가르쳐 주기 위해, 지원이 아버지는 그에게 타일들을 선물해주셨다. 그리고 이 각각의 타일들은 0 또는 1이 쓰여 있는 낱장의 타일들이다. 어느 날 짓궂은 동주가 지원이의 공부를 방해하기 위해 0이 쓰여진 낱장의 타일들을 붙여서 한 쌍으로 이루어진 00 타일들을 만들었다. 결국 현재 1 하나만으로 이루어진 타일 또는 0타일을 두 개 붙인 한 쌍의 00타일들만이 남게 되었다. ..
문제 https://www.acmicpc.net/problem/1874 1874번: 스택 수열 1부터 n까지에 수에 대해 차례로 [push, push, push, push, pop, pop, push, push, pop, push, push, pop, pop, pop, pop, pop] 연산을 수행하면 수열 [4, 3, 6, 8, 7, 5, 2, 1]을 얻을 수 있다. www.acmicpc.net 스택 (stack)은 기본적인 자료구조 중 하나로, 컴퓨터 프로그램을 작성할 때 자주 이용되는 개념이다. 스택은 자료를 넣는 (push) 입구와 자료를 뽑는 (pop) 입구가 같아 제일 나중에 들어간 자료가 제일 먼저 나오는 (LIFO, Last in First out) 특성을 가지고 있다. 1부터 n까지의 수..
1. union / union all 두 집합을 중복을 제거하고 합집합 형태로 조회, union all은 중복제거 x select A.* from (select column1 , column2 from A_table union select column3 , column4 from B_table) A; 2. || , concat 문자열 합치기 select 'My name is ' || name; from name_table; --Tom Holland-- select concat('Hi ', name, ' is my name'); from name_table; --Hi Tom Holland is my name-- 3. substring 문자열 자르기 substring(문자열, 시작점, 시작점부터 개수) se..
CASECASE 특정 조건이 충족되었을 때 SQL코드를 실행하기 위해 CASE를 사용한다. 프로그래밍 언어에서 흔히 쓰이는 IF/ELSE 문과 비슷하다. 일반적인 CASE문과 CASE 표현식으로 쓸 수 있다. 두 방법 모두 결과는 같다. -- 기본 문법 CASE WHEN condition1 THEN result1 WHEN condition2 THEN result2 ELSE some_other_result END SELECT a, CASE WHEN a = 1 THEN 'one' WHEN a = 2 THEN 'two' ELSE 'other' AS label END FROM test; -- CASE 표현식 CASE expression WHEN value1 THEN result1 WHEN value2 THEN ..
CREATE 테이블을 생성하는 명령어 -- 기본 문법 CREATE TABLE table_name( column_name TYPE column_constraint, column_name TYPE column_constraint, table_constraint table_cnostraint ) INHERITS existing_table_name; -- 더 단순한 문법 CREATE TABLE table_name( column_name TYPE column_constraint, column_name TYPE column_constraint, ); -- 예시: players 테이블 생성, player_id 컬럼은 serial pk CREATE TABLE players( player_id SERIAL PRIMARY..
AS AS문은 열이나 결과에 별칭(alias)을 부여한다. SELECT column AS new_name FROM table SELECT SUM(column) AS new_name FROM table → 컬럼명이 new_name으로 출력된다 AS연산자는 쿼리의 맨 마지막에 실행되기 때문에 WHERE, GROUP BY 호출, HAVING절 등에서는 쓸 수 없다. 정상 쿼리 SELECT customer_id, sum(amount) as total_spent from payment group by customer_id having sum(amount) > 100 실행되지 않는 쿼리, 컬럼이 없다고 뜨면서 실행되지 않는다. AS는 맨 마지막에 실행되기 때문에 alias된 컬럼명을 인식하지 못한다. SELECT ..
SQL 분류 SQL문은 DDL, DML, DCL(TCL)로 분류한다. DDL(Data Definition Language, 데이터 정의어) 데이터베이스를 정의하는 언어이며, 데이터리를 생성, 수정, 삭제하는 등의 데이터의 전체의 골격을 결정하는 역할을 하는 언어 이다. 데이터베이스, 테이블등을 생성하는 역할을 한다. CREATE, ALTER, DROP, TRUNCATE 등이 있다. DML (Data Manipulation Language, 데이터 조작어) 데이터베이스 사용자가 응용 프로그램이나 질의어를 통하여 저장된 데이터를 실질적으로 처리하는데 사용하는 언어 이다. 데이터베이스 사용자와 데이터베이스 관리 시스템 간의 인터페이스를 제공한다. SELECT, INSERT, UPDATE, DELETE 등이 있..
n개의 정수로 이루어진 임의의 수열이 주어진다. 우리는 이 중 연속된 몇 개의 수를 선택해서 구할 수 있는 합 중 가장 큰 합을 구하려고 한다. 단, 수는 한 개 이상 선택해야 한다.
예를 들어서 10, -4, 3, 1, 5, 6, -35, 12, 21, -1 이라는 수열이 주어졌다고 하자. 여기서 정답은 12+21인 33이 정답이 된다.
입력
첫째 줄에 정수 n(1 ≤ n ≤ 100,000)이 주어지고 둘째 줄에는 n개의 정수로 이루어진 수열이 주어진다. 수는 -1,000보다 크거나 같고, 1,000보다 작거나 같은 정수이다.
출력
첫째 줄에 답을 출력한다.
코드
import sys
input=sys.stdin.readline
n=int(input())
array=list(map(int, input().split()))
for i in range(1,n):
array[i]=max(array[i], array[i-1]+array[i])
print(max(array))
문제 해결
연속합을 2중 포문으로 일일히 계산하기보다 연속된 수의 합을 갱신하는 방향으로 코드를 작성하였다.
지원이에게 2진 수열을 가르쳐 주기 위해, 지원이 아버지는 그에게 타일들을 선물해주셨다. 그리고 이 각각의 타일들은 0 또는 1이 쓰여 있는 낱장의 타일들이다.
어느 날 짓궂은 동주가 지원이의 공부를 방해하기 위해 0이 쓰여진 낱장의 타일들을 붙여서 한 쌍으로 이루어진 00 타일들을 만들었다. 결국 현재 1 하나만으로 이루어진 타일 또는 0타일을 두 개 붙인 한 쌍의 00타일들만이 남게 되었다.
그러므로 지원이는 타일로 더 이상 크기가 N인 모든 2진 수열을 만들 수 없게 되었다. 예를 들어, N=1일 때 1만 만들 수 있고, N=2일 때는 00, 11을 만들 수 있다. (01, 10은 만들 수 없게 되었다.) 또한 N=4일 때는 0011, 0000, 1001, 1100, 1111 등 총 5개의 2진 수열을 만들 수 있다.
우리의 목표는 N이 주어졌을 때 지원이가 만들 수 있는 모든 가짓수를 세는 것이다. 단 타일들은 무한히 많은 것으로 가정하자.
입력
첫 번째 줄에 자연수 N이 주어진다. (1 ≤ N ≤ 1,000,000)
출력
첫 번째 줄에 지원이가 만들 수 있는 길이가 N인 모든 2진 수열의 개수를 15746으로 나눈 나머지를 출력한다.
코드
import sys
input = sys.stdin.readline
n = int(input())
dp = [0] * 1000001
dp[1] = 1
dp[2] = 2
for k in range(3,n+1):
dp[k] = (dp[k-1]+ dp[k-2])%15746
print(dp[n])
스택 (stack)은 기본적인 자료구조 중 하나로, 컴퓨터 프로그램을 작성할 때 자주 이용되는 개념이다. 스택은 자료를 넣는 (push) 입구와 자료를 뽑는 (pop) 입구가 같아 제일 나중에 들어간 자료가 제일 먼저 나오는 (LIFO, Last in First out) 특성을 가지고 있다.
1부터 n까지의 수를 스택에 넣었다가 뽑아 늘어놓음으로써, 하나의 수열을 만들 수 있다. 이때, 스택에 push하는 순서는 반드시 오름차순을 지키도록 한다고 하자. 임의의 수열이 주어졌을 때 스택을 이용해 그 수열을 만들 수 있는지 없는지, 있다면 어떤 순서로 push와 pop 연산을 수행해야 하는지를 알아낼 수 있다. 이를 계산하는 프로그램을 작성하라.
입력
첫 줄에 n (1 ≤ n ≤ 100,000)이 주어진다. 둘째 줄부터 n개의 줄에는 수열을 이루는 1이상 n이하의 정수가 하나씩 순서대로 주어진다. 물론 같은 정수가 두 번 나오는 일은 없다.
출력
입력된 수열을 만들기 위해 필요한 연산을 한 줄에 한 개씩 출력한다. push연산은 +로, pop 연산은 -로 표현하도록 한다. 불가능한 경우 NO를 출력한다.
코드
import sys
n=int(sys.stdin.readline())
stack, res, find=[],[],True
now=1
for _ in range(n):
num=int(sys.stdin.readline())
while now<=num:
stack.append(now)
res.append('+')
now+=1
if stack[-1]==num:
stack.pop()
res.append('-')
else:
find =False
if find:
for i in res:
print(i)
else:
print("NO")
select
A.*
from
(select
column1 ,
column2
from
A_table
union
select
column3 ,
column4
from
B_table) A;
2. || , concat
문자열 합치기
select
'My name is ' || name;
from
name_table;
--Tom Holland--
select
concat('Hi ', name, ' is my name');
from
name_table;
--Hi Tom Holland is my name--
3. substring
문자열 자르기 substring(문자열, 시작점, 시작점부터 개수)
select
substring('Tom Holland', 1 ,3);
--Tom--
4. to_date
문자열을 date로 변환
select
to_date('2023-03-30', 'yyyy-mm-dd');
5. to_char
숫자나 date를 문자열로 변환
select
to_char(now(), 'yyyy-mm-dd');
--2023-03-31--
'FM999,999,999' 포멧을 사용하여 숫자를 천 단위마다 컴마를 넣어 조회할 수 있다.
*포멧의 수치는 출력될 값의 예상 수치보다 높게 잡아야하며 .을 넣어서 소수점자리도 맞출 수 있다.
select
to_char(1000000, 'FM999,999,999');
--1,000,000--
6. coalesce
null값 치환
select
coalesce(name, '이름없음')
from
name_table
--name의 값이 null일 경우 '이름없음'으로 조회--
select
name ,
count(*)
from
name_table
group by
name;
--name 컬럼을 그룹화하여 name별 개수 count--
select
sum(A.cnt)
from
(select
name ,
count(*) as cnt
from
name_table
group by
lcl.jimok)as A;
--총합계--
select
round(avg(A.cnt))
from
(select
name ,
count(*) as cnt
from
name_table
group by
lcl.jimok)as A;
--평균 값을 반올림(2번째 인자로 소수점자리 지정 가능)--
select
max(A.cnt),
min(A.cnt)
from
(select
name ,
count(*) as cnt
from
name_table
group by
lcl.jimok)as A;
--최댓값과 최솟값--
select
name
from
name_table
--Tom Holland--
--Petter Parker--
--Spider-Man--
위와 같이 조회되는 값을 아래와 같이 조회 가능
select
array_to_string(array_agg(name), ',')
from
name_table
--Tom Holland,Petter Parker,Spider-Man--
-- 기본 문법
CASE
WHEN condition1 THEN result1
WHEN condition2 THEN result2
ELSE some_other_result
END
SELECT a,
CASE
WHEN a = 1 THEN 'one'
WHEN a = 2 THEN 'two'
ELSE 'other' AS label
END
FROM test;
-- CASE 표현식
CASE expression
WHEN value1 THEN result1
WHEN value2 THEN result2
ELSE some_other_result
END
SELECT a,
CASE a
WHEN 1 THEN 'one'
WHEN 2 THEN 'two'
ELSE 'other'
END
FROM test;
-- 일반 CASE 문
SELECT customer_id,
CASE
WHEN (CUSTOMER_ID <= 100) THEN 'Premium'
WHEN (CUSTOMER_ID BETWEEN 100 AND 200) THEN 'Plus'
ELSE 'Normal'
END AS customer_class
FROM customer
-- CASE 표현식
SELECT customer_id,
CASE customer_id
WHEN 2 THEN 'Winner'
WHEN 5 THEN 'Second Place'
ELSE 'Normal'
END AS raffle_results
FROM customer
SELECT
SUM(CASE rental_rate
WHEN 0.99 THEN 1
ELSE 0
END) AS bargains,
SUM(CASE rental_rate
WHEN 2.99 THEN 1
ELSE 0
END) AS regular,
SUM(CASE rental_rate
WHEN 4.99 THEN 1
ELSE 0
END) AS premium
FROM film;
CASE 연습문제
--- 영화 테이블에서 등급별 영화 개수 구하기
SELECT
SUM(CASE rating
WHEN 'R' THEN 1
ELSE 0
END) AS r,
SUM(CASE rating
WHEN 'PG' THEN 1
ELSE 0
END) AS pg,
SUM(CASE rating
WHEN 'PG-13' THEN 1
ELSE 0
END) AS pg13
FROM film
COALESCE
더 큰 덩어리로 합치다라는 뜻
처음으로 NULL이 아닌 값을 만나면 그 값을 리턴하는 함수
따라서 NULL값을 가질 수 있는 데이터를 쿼리할 때 유용하다.
SELECT COALESCE (1, 2) -> 1
SELECT COALESCE (NULL, 2, 3) -> 2
-- 할인율 컬럼이 NULL이 가능한 경우
SELECT item, (price - COALESCE(discount, 0))
AS final FROM table
CAST
CAST 연산자는 데이터 유형을 바꿔준다.
-- CAST 함수 문법
SELECT CAST('5' AS INTEGER)
SELECT CAST(date AS TIMESTAMP) FROM table
-- PostgreSQL CAST 연산자 문법
SELECT '5'::INTEGER
-- inventory_id 컬럼을 정수에서 문자열로 바꾸고 길이 재기
SELECT CHAR_LENGTH(CAST(inventory_id AS VARCHAR))
FROM rental
NULLIF
NULLIF 함수는 두 개의 인자를 받고 양쪽이 같으면 NULL을 반환하고 아니면 첫 번째 인자를 반환하는 함수이다.
NULL 값이 에러의 원인이 되거나 원하지 않는 결과가 나오는 경우에 유용하게 사용될 수 있다.
A부서 총합과 B부서 총합을 나눠서 부서별 비율을 구하는 쿼리인데, B부서 인원이 0명이 되면 0으로 나누기 에러가 난다.
SELECT (
SUM(CASE WHEN department = 'A' THEN 1 ELSE 0 END) /
SUM(CASE WHEN department = 'B' THEN 1 ELSE 0 END)
) AS department_ratio
FROM depts
NULLIF를 사용 할 경우 B부서 인원이 0이 되면 NULL을 반환하기 때문에 NULL로 나누기를 하면 값이 NULL로 바뀌고 에러가 나지 않는다.
SELECT (
SUM(CASE WHEN department = 'A' THEN 1 ELSE 0 END) /
NULLIF(SUM(CASE WHEN department = 'B' THEN 1 ELSE 0 END), 0)
) AS department_ratio
FROM depts
VIEWS
View는 SQL에서 하나 이상의 테이블(또는 다른 뷰)에서 원하는 모든 데이터를 선택하여, 그들을 사용자 정의하여 나타낸 것 이다.
뷰는 저장된 쿼리이며 가상의 테이블로 접근할 수 있다.
뷰는 단순히 쿼리를 저장한 것이고 실제로 데이터를 물리적으로 저장하는 것은 아니다.
뷰를 통해 SQL 이용의 편의성을 높일 수 있다.
뷰를 통해 원본 데이터를 조회하는 대신 데이터의 일부분만 보여주게 할 수 있기 때문에 권한관리와 보안에도 장점이 있다.
-- VIEW 생성
CREATE VIEW view_name AS SELECT clause;
-- VIEW 생성 또는 수정
-- view_name이란 뷰가 이미 있으면 수정하고 없으면 생성한다.
CREATE OR REPLACE VIEW view_name AS SELECT clause;
-- VIEW 이름 변경
ALTER VIEW view_name RENAME to renamed_view_name
-- VIEW 삭제
DROP VIEW view_name;
CREATE VIEW customer_info AS
SELECT first_name, last_name, address
FROM customer
INNER JOIN address
ON customer.address_id = address.address_id
SELECT * FROM customer_info
-- SELECT에 district 컬럼 추가
CREATE OR REPLACE VIEW customer_info AS
SELECT first_name, last_name, address, district
FROM customer
INNER JOIN address
ON customer.address_id = address.address_id
특정 조건이 충족되었을 때 SQL코드를 실행하기 위해 CASE를 사용한다.
프로그래밍 언어에서 흔히 쓰이는 IF/ELSE 문과 비슷하다.
일반적인 CASE문과 CASE 표현식으로 쓸 수 있다. 두 방법 모두 결과는 같다.
-- 기본 문법
CASE
WHEN condition1 THEN result1
WHEN condition2 THEN result2
ELSE some_other_result
END
SELECT a,
CASE
WHEN a = 1 THEN 'one'
WHEN a = 2 THEN 'two'
ELSE 'other' AS label
END
FROM test;
-- CASE 표현식
CASE expression
WHEN value1 THEN result1
WHEN value2 THEN result2
ELSE some_other_result
END
SELECT a,
CASE a
WHEN 1 THEN 'one'
WHEN 2 THEN 'two'
ELSE 'other'
END
FROM test;
-- 일반 CASE 문
SELECT customer_id,
CASE
WHEN (CUSTOMER_ID <= 100) THEN 'Premium'
WHEN (CUSTOMER_ID BETWEEN 100 AND 200) THEN 'Plus'
ELSE 'Normal'
END AS customer_class
FROM customer
-- CASE 표현식
SELECT customer_id,
CASE customer_id
WHEN 2 THEN 'Winner'
WHEN 5 THEN 'Second Place'
ELSE 'Normal'
END AS raffle_results
FROM customer
SELECT
SUM(CASE rental_rate
WHEN 0.99 THEN 1
ELSE 0
END) AS bargains,
SUM(CASE rental_rate
WHEN 2.99 THEN 1
ELSE 0
END) AS regular,
SUM(CASE rental_rate
WHEN 4.99 THEN 1
ELSE 0
END) AS premium
FROM film;
CASE 연습문제
--- 영화 테이블에서 등급별 영화 개수 구하기
SELECT
SUM(CASE rating
WHEN 'R' THEN 1
ELSE 0
END) AS r,
SUM(CASE rating
WHEN 'PG' THEN 1
ELSE 0
END) AS pg,
SUM(CASE rating
WHEN 'PG-13' THEN 1
ELSE 0
END) AS pg13
FROM film
COALESCE
더 큰 덩어리로 합치다라는 뜻
처음으로 NULL이 아닌 값을 만나면 그 값을 리턴하는 함수
따라서 NULL값을 가질 수 있는 데이터를 쿼리할 때 유용하다.
SELECT COALESCE (1, 2) -> 1
SELECT COALESCE (NULL, 2, 3) -> 2
-- 할인율 컬럼이 NULL이 가능한 경우
SELECT item, (price - COALESCE(discount, 0))
AS final FROM table
CAST
CAST 연산자는 데이터 유형을 바꿔준다.
-- CAST 함수 문법
SELECT CAST('5' AS INTEGER)
SELECT CAST(date AS TIMESTAMP) FROM table
-- PostgreSQL CAST 연산자 문법
SELECT '5'::INTEGER
-- inventory_id 컬럼을 정수에서 문자열로 바꾸고 길이 재기
SELECT CHAR_LENGTH(CAST(inventory_id AS VARCHAR))
FROM rental
NULLIF
NULLIF 함수는 두 개의 인자를 받고 양쪽이 같으면 NULL을 반환하고 아니면 첫 번째 인자를 반환하는 함수이다.
NULL 값이 에러의 원인이 되거나 원하지 않는 결과가 나오는 경우에 유용하게 사용될 수 있다.
A부서 총합과 B부서 총합을 나눠서 부서별 비율을 구하는 쿼리인데, B부서 인원이 0명이 되면 0으로 나누기 에러가 난다.
SELECT (
SUM(CASE WHEN department = 'A' THEN 1 ELSE 0 END) /
SUM(CASE WHEN department = 'B' THEN 1 ELSE 0 END)
) AS department_ratio
FROM depts
NULLIF를 사용 할 경우 B부서 인원이 0이 되면 NULL을 반환하기 때문에 NULL로 나누기를 하면 값이 NULL로 바뀌고 에러가 나지 않는다.
SELECT (
SUM(CASE WHEN department = 'A' THEN 1 ELSE 0 END) /
NULLIF(SUM(CASE WHEN department = 'B' THEN 1 ELSE 0 END), 0)
) AS department_ratio
FROM depts
VIEWS
View는 SQL에서 하나 이상의 테이블(또는 다른 뷰)에서 원하는 모든 데이터를 선택하여, 그들을 사용자 정의하여 나타낸 것 이다.
뷰는 저장된 쿼리이며 가상의 테이블로 접근할 수 있다.
뷰는 단순히 쿼리를 저장한 것이고 실제로 데이터를 물리적으로 저장하는 것은 아니다.
뷰를 통해 SQL 이용의 편의성을 높일 수 있다.
뷰를 통해 원본 데이터를 조회하는 대신 데이터의 일부분만 보여주게 할 수 있기 때문에 권한관리와 보안에도 장점이 있다.
-- VIEW 생성
CREATE VIEW view_name AS SELECT clause;
-- VIEW 생성 또는 수정
-- view_name이란 뷰가 이미 있으면 수정하고 없으면 생성한다.
CREATE OR REPLACE VIEW view_name AS SELECT clause;
-- VIEW 이름 변경
ALTER VIEW view_name RENAME to renamed_view_name
-- VIEW 삭제
DROP VIEW view_name;
CREATE VIEW customer_info AS
SELECT first_name, last_name, address
FROM customer
INNER JOIN address
ON customer.address_id = address.address_id
SELECT * FROM customer_info
-- SELECT에 district 컬럼 추가
CREATE OR REPLACE VIEW customer_info AS
SELECT first_name, last_name, address, district
FROM customer
INNER JOIN address
ON customer.address_id = address.address_id
-- 기본 문법
CREATE TABLE table_name(
column_name TYPE column_constraint,
column_name TYPE column_constraint,
table_constraint table_cnostraint
) INHERITS existing_table_name;
-- 더 단순한 문법
CREATE TABLE table_name(
column_name TYPE column_constraint,
column_name TYPE column_constraint,
);
-- 예시: players 테이블 생성, player_id 컬럼은 serial pk
CREATE TABLE players(
player_id SERIAL PRIMARY KEY,
age SMALLINT NOT NULL
);
CREATE TABLE account(
user_id SERIAl PRIMARY KEY,
username VARCHAR(50) UNIQUE NOT NULL,
password VARCHAR(50) NOT NULL,
email VARCHAR(250) UNIQUE NOT NULL,
created_on TIMESTAMP NOT NULL,
last_login TIMESTAMP
)
CREATE TABLE job(
job_id SERIAL PRIMARY KEY,
job_name VARCHAR(200) UNIQUE NOT NULL
);
UPDATE account
SET last_login = CURRENT_TIMESTAMP
WHERE last_login IS NULL;
모든last_login컬럼 값을created_on의 값으로 수정
UPDATE account
SET last_login = created_on;
다른 테이블의 값 사용
UPDATE tableA
SET original_col = tableB.new_col
FROM tableB
WHERE tableA.id = tableB.id;
RETURNING:RETURNING이 없으면 CRUD 쿼리를 실행한 후에 그냥 쿼리가 실행됐다고만 뜨는데RETURNING을 사용하면 실행한 쿼리의 결과를 SELECT한 것처럼 보여준다.
UPDATE account
SET last_login = created_on
RETURNING account_id, last_login;
예제
UPDATE account
SET last_login = CURRENT_TIMESTAMP;
UPDATE account
SET last_login = created_on;
UPDATE account_job
SET hire_date = account.created_on
FROM account
WHERE account_job.user_id = account.user_id
UPDATE account
SET last_login = CURRENT_TIMESTAMP
RETURNING email, created_on, last_login
DELETE
테이블의 데이터를 삭제하는 명령어
-- 기본 문법
DELETE FROM table
WHERE row_id = 1
다른 테이블에 있는 행 지우기
DELETE FROM tableA
USING tableB
WHERE tableA.id = tableB.id
테이블의 모든 행 지우기
DELETE FROM table
RETURNING사용 가능
DELETE FROM job
WHERE job_name = 'Cowboy'
RETURNING job_id, job_name
ALTER
이미 존재하는 테이블의 구조를 변경하는 명령어
컬럼 추가, 삭제, 변경, 기본값 지정, 제약조건 추가 등의 작업을 할 수 있다.
-- 기본 문법
ALTER TABLE table_name action
-- 컬럼 추가
ALTER TABLE table_name
ADD COLUMN new_col TYPE
-- 컬럼 삭제
ALTER TABLE table_name
DROP COLUMN col_name
-- 제약 조건 변경
ALTER TABLE table_name
ALTER COLUMN col_name
ADD CONSTRAINT constraint_name
예제
-- 테이블명 변경
ALTER TABLE information
RENAME TO new_info
-- 컬럼명 변경
ALTER TABLE new_info
RENAME COLUMN person TO people
-- 제약조건 변경: null 허용
ALTER TABLE new_info
ALTER COLUMN people DROP NOT NULL
DROP
테이블의 컬럼을 삭제하는 명령어
PostgreSQL에서 DROP을 실행하면 삭제되는 컬럼에 관련된 모든 인덱스와 제약조건 또한 삭제한다.
단 뷰, 트리거, 저장 프로시저에 연관된 컬럼은CASCADE조건이 없으면 삭제되지 않는다.
-- 기본 문법
ALTER TABLE table_name
DROP COLUMN col_name
-- 존재하지 않는 컬럼에 대한 에러 방지
ALTER TABLE table_name
DROP COLUMN IF EXISTS col_name
-- 여러 컬럼 삭제
ALTER TABLE table_name
DROP COLUMN col_one,
DROP COLUMN col_two
예제
ALTER TABLE new_info
DROP COLUMN people
ALTER TABLE new_info
DROP COLUMN IF EXISTS people
CHECK
특정 조건에 맞춘 제약조건을 쓸 수 있게 해주는 명령어
-- 기본 문법
CHECK (conditions)
CREATE TABLE example(
ex_id SERIAl PRIMARY KEY,
age SMALLINT CHECK (age > 21),
parent_age SMALLINT CHECK(parent_age > age)
);
CREATE TABLE employees(
emp_id SERIAl PRIMARY KEY,
first_name VARCHAR(50) NOT NULL,
last_nmae VARCHAR(50) NOT NULL,
birthdate DATE CHECK (birthdate > '1900-01-01'),
hire_date DATE CHECK (hire_date > birthdate),
salary INTEGER CHECK (salary > 0)
)
INSERT INTO employees(
first_name,
last_name,
birthdate,
hire_date,
salary
)
VALUES(
'Jose',
'Portilla',
'1899-11-03', -- 제약 조건 위반으로 insert 안됨
'2010-01-01',
100
)
연습문제
CREATE TABLE students(
student_id SERIAL PRIMARY KEY,
first_name VARCHAR(50) NOT NULL,
last_name VARCHAR(50) NOT NULL,
homeroom_number INTEGER CHECK(homeroom_number > 0),
phone VARCHAR(500) UNIQUE NOT NULL,
email VARCHAR(250) UNIQUE,
graduation_year INTEGER CHECK(graduation_year > 0)
);
CREATE TABLE teachers(
teacher_id SERIAL PRIMARY KEY,
first_name VARCHAR(50) NOT NULL,
last_name VARCHAR(50) NOT NULL,
homeroom_number INTEGER CHECK(homeroom_number > 0),
department VARCHAR(50),
phone VARCHAR(500) UNIQUE,
email VARCHAR(250) UNIQUE
);
SELECT SUM(column) AS new_name FROM table→ 컬럼명이 new_name으로 출력된다
AS연산자는 쿼리의 맨 마지막에 실행되기 때문에 WHERE, GROUP BY 호출, HAVING절 등에서는 쓸 수 없다.
정상 쿼리 SELECT customer_id, sum(amount) as total_spent from payment group by customer_id having sum(amount) > 100
실행되지 않는 쿼리, 컬럼이 없다고 뜨면서 실행되지 않는다. AS는 맨 마지막에 실행되기 때문에 alias된 컬럼명을 인식하지 못한다. SELECT customer_id, sum(amount) as total_spent from payment group by customer_id having total_spent > 100
정상 쿼리 SELECT customer_id, amount as new_name from payment where amount > 2
실행되지 않는 쿼리 SELECT customer_id, amount as new_name from payment where new_name > 2
JOIN
여러 테이블의 레코드를 결합하여 하나의 열로 표현하는 것
결합된 테이블 중 하나에만 존재하는 정보를 처리하는 방식에 따라 분류한다.
하나의 쿼리에서 연달아 여러 개의 JOIN을 적용할 수 있다.
ANSI 표준 SQL은 다음 다섯 가지 유형의 JOIN을 규정한다.
INNER
FULL OUTER
LEFT OUTER
RIGHT OUTER
CROSS
예제 데이터 테이블, 이름은 모두 고유한 이름이라고 가정.
Registrations
reg_id
name
1
Andrew
2
Bob
3
Charlie
4
David
Logins
log_id
name
1
Xavier
2
Andrew
3
Yolanda
4
Bob
INNER JOIN
두 테이블 모두에서 일치하는 레코드를 조회하는 것
대칭적이기 때문에 테이블 순서를 바꿔도 결과는 같다.
SELECT * FROM TableA INNER JOIN TableB ON TableA.col_match = TableB.col_match;
SELECT * FROM TableB INNER JOIN TableA ON TableB.col_match = TableA.col_match;
PostgreSQL에서는 그냥 JOIN이라고 쓰면 INNER JOIN으로 인식한다.
SELECT * FROM Registrations
INNER JOIN Logins
ON Registrations.name = Logins.name;
Results
reg_id name log_id name
1 Andrew 2 Andrew
3 Bob 4 Bob
양쪽에서 조회하려는 컬럼명이 같은 경우 어떤 테이블에 있는 컬럼인지 명시해줘야 한다.
SELECT payment_id, payment.customer_id, first_name
FROM payment
INNER JOIN customer
ON payment.customer_id = customer.customer_id
FULL OUTER JOIN
테이블A와 B의 가능한 모든 레코드를 조합한다.
서로 일치하는 데이터가 없으면 null로 표시된다.
대칭적이기 때문에 테이블 순서를 바꿔도 결과는 같다.
SELECT * FROM TableA FULL OUTER JOIN TableB ON TableA.col_match = TableB.col_match;
SELECT * FROM Registrations
FULL OUTER JOIN Logins
ON Registrations.name = Logins.name;
Results
reg_id name log_id name
1 Andrew 2 Andrew
2 Bob 4 Bob
3 Charlie null null
4 David null null
null null 1 Xavier
null null 3 Yolanda
FULL OUTER JOIN에 WHERE문을 활용하여 양쪽 테이블에서 고유한 값을 조회할 수 있다.
대칭적이기 때문에 테이블 순서를 바꿔도 결과는 같다.
INNER JOIN의 정반대인 결과가 나온다.
SELECT * FROM TableA FULL OUTER JOIN TableB ON TableA.col_match = TableB.col_match WHERE TableA.id IS null OR TableB.id IS null;
SELECT * FROM Registrations
FULL OUTER JOIN Logins
ON Registrations.name = Logins.name
WHERE Registrations.reg_id IS null OR Logins.log_id IS null
Results
reg_id name log_id name
3 Charlie null null
4 David null null
null null 1 Xavier
null null 3 Yolanda
LEFT OUTER JOIN (LEFT JOIN)
왼쪽 테이블에 있는 레코드 세트를 출력하고 오른쪽 테이블에 일치하는 데이터가 없으면 null로 출력한다.
벤 다이어그램으로 보듯이 대칭적이지 않다. 따라서 테이블 순서가 중요하다.
SELECT * FROM TableA LEFT OUTER JOIN TableB ON TableA.col_match = TableB.col_match;
SELECT * FROM Registrations
LEFT OUTER JOIN Logins
ON Registrations.name = Logins.name
Results
reg_id name log_id name
1 Andrew 2 Andrew
2 Bob 4 Bob
3 Charlie null null
4 David null null
테이블A에만 있고 B에는 없는 행을 구하기 위해 LEFT OUTER JOIN을 이용하면서 WHERE절 조건을 활용하는 방법
대칭적이지 않기 때문에 테이블 순서가 중요하다.
SELECT * FROM TableA LEFT OUTER JOIN TableB ON TableA.col_match = TableB.col_match WHERE TableB.id IS NULL
SELECT * FROM Registrations
LEFT OUTER JOIN Logins
ON Registrations.name = Logins.name
WHERE Logins.log_id IS NULL
Results
reg_id name log_id name
3 Charlie null null
4 David null null
RIGHT OUTER JOIN (RIGHT JOIN)
기본적으로 LEFT OUTER JOIN과 완전히 동일하지만 테이블이 서로 바뀐다는 점만 다르다.
LEFT JOIN을 쓰면서 테이블 순서만 바꿔줘도 동일한 결과를 얻을 수 있다.
SELECT * FROM TableA RIGHT OUTER JOIN TableB ON TableA.col_match = TableB.col_match;
테이블B에만 있는 데이터를 조회하기 위해 LEFT JOIN과 마찬가지로 WHERE를 활용할 수 있다.
SELECT * FROM TableA RIGHT OUTER JOIN TableB ON TableA.col_match = TableB.col_match WHERE TableA.id IS null;
SELF JOIN
동일 테이블 사이의 조인, 테이블을 구별하기 위해 서로 다른 별칭을 사용해야 한다.
SELECT tableA.col, tableB.col
FROM table AS tableA
JOIN table AS tableB
ON tableA.som_col = tableB.other_col
-- 같은 영화 테이블 안에서, 영화 별로 상영시간이 같은 영화의 목록 구하기
SELECT f1.title, f2.title, f1.length
FROM film AS f1
INNER JOIN film AS f2
ON f1.film_id != f2.film_id AND f1.length = f2.length
JOIN 연습문제
캘리포니아에 살고 있는 고객의 이메일은 무엇인가?
SELECT district, email
FROM address
INNER JOIN customer ON address.address_id = customer.address_id
WHERE district = 'California'
닉 월버그(Nick Wahlberg)라는 배우가 출연한 모든 영화 목록 찾기
SELECT title, first_name, last_name
FROM film_actor
INNER JOIN actor ON film_actor.actor_id = actor.actor_id
INNER JOIN film ON film_actor.film_id = film.film_id
WHERE first_name = 'Nick' AND last_name = 'Wahlberg'
테니스 코트(facid 0, 1)의 2012년 9월 21일의 예약 시작시간 목록을 구하고 시작시간 오름차순으로 정렬하라
SELECT cd.bookings.starttime, cd.facilities.name
FROM cd.facilities
INNER JOIN cd.bookings ON cd.facilities.facid = cd.bookings.facid
WHERE cd.facilities.facid IN (0, 1)
AND cd.bookings.starttime >= '2012-09-21'
AND cd.bookings.starttime <= '2012-09-22'
ORDER BY cd.bookings.starttime
David Farrell이란 회원의 예약 시작 시간을 구하라
SELECT cd.bookings.starttime
FROM cd.bookings
INNER JOIN cd.members
ON cd.bookings.memid = cd.members.memid
WHERE cd.members.firstname = 'David' AND surname = 'Farrell'
UNION
UNION 연산자는 두 개 이상의 SELECT문의 결과 세트를 결합하기 위해 사용된다.
JOIN과 UNION의 기본적인 차이는 UNION은 두 결과를 직접 붙인다는 것이다.
SELECT column_name(s) FROM table1 UNION SELECT column_name(s) FROM table2;
SELECT문이 논리적이어야 하고 서로의 바로 위에 결과를 쌓을 수 있도록 열이 일치해야 한다.
ORDER BY로 정렬할 수 있다.
예제 테이블
Sales_2021_Q1
name
amount
David
100
Claire
50
Sales_2021_Q2
name
amount
David
200
Claire
100
SELECT * FROM Sales2021_Q1 UNION SELECT * FROM Sales2021_Q2;
Results
name amount
David 100
Claire 50
David 200
Claire 100