-- New Table
CREATE TABLE people (
    name VARCHAR(100),
    birthdate DATE,
    birthtime TIME,
    birthdt DATETIME
);
 
INSERT INTO people (name, birthdate, birthtime, birthdt)
VALUES
('Elton', '2000-12-25', '11:00:00', '2000-12-25 11:00:00'),
('Lulu', '1985-04-11', '9:45:10', '1985-04-11 9:45:10'),
('Juan', '2020-08-15', '23:59:00', '2020-08-15 23:59:00'),
('Hazel', '2022-10-05', '14:58:29', '2022-10-05 14:58:29');

밑에서 실행할 예제는 이전 글에서 사용한 테이블과 데이터를 사용한다.

또한, 추가적으로 사용하는 테이블과 데이터가 있어서 위의 코드를 참고하자.

Colt Steele의 SQL 데이터를 참고했음을 알린다.

 

NOT

부정을 의미하는 NOT 예약어이다.

어떤 행동의 반대되는 결과를 반환하거나 수행한다.

 

-- NOT EQUAL
SELECT title FROM books WHERE released_year != 2017;
SELECT title FROM books WHERE NOT released_year = 2017;
SELECT title, author_lname FROM books WHERE author_lname != 'Gaiman';
SELECT title, author_lname FROM books WHERE NOT author_lname = 'Gaiman';

같지 않다의 의미로 사용할 수 있다. NOT을 사용해도 되고, != 연산자를 사용해도 된다.

첫 번째와 두 번째 예시가 동일하고, 세 번째와 네 번째 에시가 동일하다.

첫 번째 예시는 realeased_year가 2017이 아닌 것만 골라서 title을 반환한다.

세 번째 예시는 author_lname이 Gaiman이 아닌 경우에만 골라서 title과 author_lname을 반환한다.

 

-- NOT LIKE
SELECT title FROM books WHERE title NOT LIKE '% %';
SELECT title FROM books WHERE title NOT LIKE '%e%';
SELECT author_fname FROM books WHERE author_fname NOT LIKE 'da%';

와일드카드를 사용하는 LIKE에도 사용할 수 있다.

첫 번째 예시는 title에서 공백을 포함하지 않는 경우에만 title을 반환한다.

두 번째 예시는 title에서 e를 포함하지 않는 경우에만 title을 반환한다.

세 번째 예시는 author_fname에서 da로 시작하지 않는 경우에만 author_fname을 반환한다.

LIKE는 부정을 뜻하는 ! 연산을 사용할 수 없다. !LIKE가 아닌 NOT LIKE만 사용 가능하다.

 

-- COMPARE OPERATORS --
-- GREATER THAN
SELECT title, released_year FROM books WHERE released_year > 2000;
SELECT title, pages FROM books WHERE pages > 500;
SELECT 99 > 1; -- boolean: 1
SELECT 1 > NULL; -- NULL

비교 연산자 >, <, >=, <= 네 가지다.

등호(=)를 붙일 때는 반드시 오른편에 써야한다. =>는 인식하지 못하고 >=로 작성해야 한다.

첫 번째 예시는 realeased_year가 2000보다 큰 경우에만 title과 released_year를 반환한다.

세 번째 예시는 단순한 수식이다. 비교 연산만을 SELECT로 연산하면 boolean을 반환한다.

즉, 99가 1보다 큰 것은 사실이므로, 1을 반환한다.

네 번째 예시에서 NULL은 비교 대상이 될 수 없다. 따라서 NULL을 반환한다.

 

-- LESS THAN
SELECT title, released_year FROM books WHERE released_year < 2000 ORDER BY released_year;
SELECT title, pages FROM books WHERE pages < 200;

-- GREATER THAN or EQUAL TO
SELECT title, released_year FROM books WHERE released_year >= 2010 ORDER BY released_year;

-- LESS THAN or EQUAL TO
SELECT title, released_year FROM books WHERE released_year <= 2010 ORDER BY released_year DESC;

위에서 사용한 GREATER THAN과 방향이 반대이다.

>나 <를 사용할 경우 비교 대상을 포함하지 않는다. 이때 =를 사용하면 비교 대상을 포함하여 연산한다.

많은 프로그래밍 언어에서 사용하고 있는 규칙과 동일하다.

 

-- LOGICAL OPERATORS --
-- AND
SELECT title, author_lname, released_year
FROM books
WHERE author_lname = 'Eggers'
    AND released_year > 2010;
    
SELECT title, author_lname, released_year
FROM books
WHERE author_lname = 'Eggers'
    AND released_year >= 2010
    AND title LIKE '%novel%';

SELECT title, pages
FROM books
WHERE CHAR_LENGTH(title) > 30
    AND pages > 500;

논리 연산자인 AND, OR다. 부울대수에 나오는 개념으로 진리값(boolean)을 활용한 논리 판별 연산자이다.

쉽게 말하면 AND는 두 값이 모두 참일 때만 참이고, OR는 두 값 중 하나라도 참일 때 참을 반환한다.

첫 번째 예시는 author_lname이 Eggers이면서 released_year가 2010보다 큰 경우에만 3개의 열을 반환한다.

두 번째 예시는 WHERE에서 AND를 두 번 이상 사용하였다. 이처럼 논리 연산자를 여러 개 사용하는 것도 가능하다.

세 번째 예시는 title의 길이가 30보다 길면서 pages가 500보다 큰 경우에만 title과 pages를 반환한다.

 

SELECT title, released_year FROM books
WHERE released_year % 2 = 1 AND released_year >= 2000;

다른 프로그래밍 언어와 마찬가지로 SQL에서도 % 연산자를 사용할 수 있다.

%는 나머지 연산자(modular)로 A % B라면, A를 B로 나눈 나머지를 반환한다.

따라서 위의 예시는 realeased_year가 홀수이면서 2000보다 큰 경우에만 title과 released_year를 반환한다.

 

-- OR
SELECT title, author_lname, released_year
FROM books
WHERE author_lname = 'Eggers'
    OR released_year > 2010;

SELECT title, pages
FROM books
WHERE pages < 200
    OR title LIKE '%stories%';

AND는 모든 조건을 만족해야하지만, OR는 조건을 하나라도 만족하면 된다.

AND에서는 author_lname이 Eggers면서 released_year가 2010보다 큰 경우만 데이터를 뽑아냈다.

첫 번째 예시는 OR에서는 Eggers이거나 2010보다 큰 경우, 하나라도 만족할 경우 데이터를 뽑아낸다.

두 번째 예시는 와일드카드를 사용하여 OR 조건으로 데이터를 뽑아냈다.

 

-- BETWEEN
SELECT title, released_year FROM books WHERE 2004 <= released_year AND released_year <= 2014;
SELECT title, released_year FROM books WHERE released_year BETWEEN 2004 AND 2014;

SELECT title, released_year FROM books WHERE 2004 > released_year OR released_year > 2014;
SELECT title, released_year FROM books WHERE released_year NOT BETWEEN 2004 AND 2014;

첫 번째 예시처럼 released_year가 2004보다 크거나 같고 2014보다 작거나 같은 경우를 뽑을 수 있다.

이를 두 번째 예시처럼 간단하게 BETWEEN을 사용하여 표현할 수 있다. 이때 두 경곗값을 포함한다.

BETWEEN도 처음에 사용한 NOT을 사용할 수 있다.

 

-- A note about comparing date
SELECT * FROM people WHERE birthdate < '2005-01-01';
SELECT * FROM people WHERE YEAR(birthdate) < 2005;
SELECT * FROM people WHERE birthtime > '09:00:00';
SELECT * FROM people WHERE HOUR(birthtime) > 9;

비교 연산자(>, < 등)를 사용하여 날짜를 비교하는 것도 가능하다.

첫 번째와 세 번째 예시처럼 SQL에서는 기본적으로 문자열과 날짜를 비교하는 것을 지원한다.

두 번째와 네 번째 예시처럼 날짜 데이터와 숫자를 비교하는 것 또한 가능하다.  

 

-- 기본 구문
CAST(sample_date AS want_type)

-- 예시
SELECT CAST('09:00:00' AS TIME);

CAST 함수를 사용하여 데이터의 자료형을 변경할 수 있다.

예를 들어 '09:00:00'은 문자열 자료형이다. 이를 TIME 자료형으로 변경할 수 있다.

 

SELECT * FROM people WHERE birthtime BETWEEN '12:00:00' AND '16:00:00';

SELECT * FROM people WHERE birthtime
BETWEEN CAST('12:00:00' AS TIME) AND CAST('16:00:00' AS TIME);

SELECT * FROM people WHERE HOUR(birthtime)
BETWEEN 12 AND 16;

BETWEEN과 CAST를 활용한 날짜 데이터 비교다.

실제로 SQL 공식 docs에서도 비교 연산자보다는 BETWEEN을 통한 비교를 권장하고 있다.

위에서 언급했듯이, SQL에서 날짜 데이터는 문자열 데이터와 비교 가능하다.

첫 번째 예시는 12시부터 16시 사이에 해당하는 birthtime만을 골라 모든 열을 반환한다.

두 번째 예시는 첫 번째 예시와 동일한 결과를 반환하지만, CAST로 비교하는 자료형을 TIME으로 바꾸었다.

세 번째 예시는 birthtime를 HOUR 함수로 시간만을 추출하여, BETWEEN으로 비교한다. 

 

-- IN
SELECT title, author_lname FROM books
WHERE author_lname = 'Carver' OR author_lname = 'Lahiri' OR author_lname = 'Smith';

SELECT title, author_lname FROM books
WHERE author_lname IN ('Carver', 'Lahiri', 'Smith');

SELECT title, author_lname FROM books
WHERE author_lname NOT IN ('Carver', 'Lahiri', 'Smith');

IN 연산자는 존재하는 여러 개의 데이터에 값이 있는지 확인하는 연산이다. Python의 in과 동일하다.

첫 번째 예시와 두 번째 예시는 같은 결과를 반환한다.

첫 번째 예시는 OR 연산자를 사용하여 author_lname를 3개 중에서 있는지 확인하는 코드다.

두 번째 예시는 IN 연산자를 사용하여 간단하게 3개의 유무를 확인한다.

세 번째 예시처럼 마찬가지로 NOT 연산자를 사용할 수 있다.

 

-- CASE STATEMENTS
SELECT title, released_year,
    CASE
        WHEN released_year >= 2000 THEN 'Modern Lit'
        ELSE '20th Centiry Lit'
    END AS GENRE
FROM books;

SELECT title, stock_quantity,
    CASE
        WHEN stock_quantity BETWEEN 0 AND 50 THEN '*'
        WHEN stock_quantity BETWEEN 51 AND 100 THEN '**'
        ELSE '***'
    END AS STOCK
FROM books;

SELECT title, stock_quantity,
    CASE
        WHEN stock_quantity <= 50 THEN '*'
        WHEN stock_quantity <= 100 THEN '**'
        ELSE '***'
    END AS STOCK
FROM books;

다른 프로그래밍 언어의 if-else if-else와 같은 조건문이 SQL에도 존재한다.

대신 다른 키워드를 사용하여 CASE-WHEN-THEN-ELSE-END 구문으로 돌아간다.

CASE로 조건문을 시작함을 알리고, END로 조건문이 끝남을 알린다.

WHEN으로 조건문을 작성하고, 이에 해당하는 결과를 THEN에 작성한다.

마지막에 ELSE는 조건문 없이 나머지에 해당하는 결과만을 작성한다.

 

-- IS NULL
SELECT * FROM books WHERE author_lname IS NULL;
SELECT * FROM books WHERE author_lname IS NOT NULL;

위에서 NULL을 비교하는 것은 불가능하다고 했다.

따라서 SQL에서 NULL인지 아닌지 확인하기 위해서는 IS NULL을 사용한다.

마찬가지로 NOT을 사용하여 IS NOT NULL을 사용하여 NULL이 아닌지 확인할 수 있다.

 

 

-- 실습 Q1
SELECT title, released_year FROM books WHERE released_year < 1980;

-- 실습 Q2
SELECT title, author_lname FROM books WHERE author_lname IN ('Eggers', 'Chabon');

-- 실습 Q3
SELECT title, author_lname, released_year FROM books
WHERE author_lname = 'Lahiri' AND released_year > 2000;

-- 실습 Q4
SELECT title, pages FROM books WHERE pages BETWEEN 100 AND 200;

-- 실습 Q5
SELECT title, author_lname FROM books
WHERE author_lname LIKE 'C%' OR author_lname LIKE 'S%';
SELECT title, author_lname FROM books
WHERE SUBSTR(author_lname, 1, 1) IN ('C', 'S');

-- 실습 Q6
SELECT title, author_lname,
    CASE
        WHEN title LIKE '%stories%' THEN 'Short Stories'
        WHEN title LIKE '%kids%' or title LIKE '%heartbreaking%' THEN 'Memoir'
        ELSE 'Novel'
	END AS TYPE
FROM books;

-- 실습 Q7
SELECT author_fname, author_lname,
    CASE
        WHEN COUNT(*) = 1 THEN CONCAT('1 book')
        ELSE CONCAT(COUNT(*), ' books')
	END AS COUNT
FROM books
GROUP BY author_fname, author_lname;

여러 가지 다양한 실습들이다. 직접 테스트하면서 연산자에 익숙해지자.

'Language > SQL' 카테고리의 다른 글

SQL One-to-Many Relationship  (0) 2023.10.02
SQL CONSTRAINT, ALTER  (0) 2023.09.26
SQL DATA TYPE  (0) 2023.09.19
SQL 집계 함수  (0) 2023.09.17
SQL 부분 조회(필터링)  (0) 2023.09.15

+ Recent posts