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 등이 있..
문제 https://www.acmicpc.net/problem/1850 1850번: 최대공약수 모든 자리가 1로만 이루어져있는 두 자연수 A와 B가 주어진다. 이때, A와 B의 최대 공약수를 구하는 프로그램을 작성하시오. 예를 들어, A가 111이고, B가 1111인 경우에 A와 B의 최대공약수는 1이고, A www.acmicpc.net 모든 자리가 1로만 이루어져있는 두 자연수 A와 B가 주어진다. 이때, A와 B의 최대 공약수를 구하는 프로그램을 작성하시오. 예를 들어, A가 111이고, B가 1111인 경우에 A와 B의 최대공약수는 1이고, A가 111이고, B가 111111인 경우에는 최대공약수가 111이다. 입력 첫째 줄에 두 자연수 A와 B를 이루는 1의 개수가 주어진다. 입력되는 수는 263..
문제 https://www.acmicpc.net/problem/1783 1783번: 병든 나이트 첫째 줄에 체스판의 세로 길이 N와 가로 길이 M이 주어진다. N과 M은 2,000,000,000보다 작거나 같은 자연수이다. www.acmicpc.net 병든 나이트가 N × M 크기 체스판의 가장 왼쪽아래 칸에 위치해 있다. 병든 나이트는 건강한 보통 체스의 나이트와 다르게 4가지로만 움직일 수 있다. 2칸 위로, 1칸 오른쪽 1칸 위로, 2칸 오른쪽 1칸 아래로, 2칸 오른쪽 2칸 아래로, 1칸 오른쪽 병든 나이트는 여행을 시작하려고 하고, 여행을 하면서 방문한 칸의 수를 최대로 하려고 한다. 병든 나이트의 이동 횟수가 4번보다 적지 않다면, 이동 방법을 모두 한 번씩 사용해야 한다. 이동 횟수가 4번보..
-- 기본 문법
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
병든 나이트가 N × M 크기 체스판의 가장 왼쪽아래 칸에 위치해 있다. 병든 나이트는 건강한 보통 체스의 나이트와 다르게 4가지로만 움직일 수 있다.
2칸 위로, 1칸 오른쪽
1칸 위로, 2칸 오른쪽
1칸 아래로, 2칸 오른쪽
2칸 아래로, 1칸 오른쪽
병든 나이트는 여행을 시작하려고 하고, 여행을 하면서 방문한 칸의 수를 최대로 하려고 한다. 병든 나이트의 이동 횟수가 4번보다 적지 않다면, 이동 방법을 모두 한 번씩 사용해야 한다. 이동 횟수가 4번보다 적은 경우(방문한 칸이 5개 미만)에는 이동 방법에 대한 제약이 없다.
체스판의 크기가 주어졌을 때, 병든 나이트가 여행에서 방문할 수 있는 칸의 최대 개수를 구해보자.
입력
첫째 줄에 체스판의 세로 길이 N와 가로 길이 M이 주어진다. N과 M은 2,000,000,000보다 작거나 같은 자연수이다.
출력
병든 나이트가 여행에서 방문할 수 있는 칸의 개수중 최댓값을 출력한다.
코드
import sys
input=sys.stdin.readline
n, m=map(int, input().split())
if n == 1:
print(1)
elif n == 2:
print(min(4, (m-1)//2+1))
elif m <= 6:
print(min(4, m))
else:
print(m-2)
문제 해결
처음엔 DFS와 BFS를 이용하는 문제인 줄 알았으나, 나이트의 움직임이 4가지로 정해져 있어서 위아래와 오른쪽 방향으로만 정해져있어서 조건 분기, 그리디로 풀 수 있는 문제였다.