표준 SQL에서는 FROM을 생략할 수 없다.
SELECT LLENGTH('AAAAA') AS length;
SELECT문은 프로그램, 컬럼은 변수 역할
SELECT name, buyPrice * quantityInStock FROM products;
SELCT 실행 순서
5.SELECT
1.FROM
2.WHERE
3.GROUP BY
4.HAVING
6.ORDER BY
중복값 제거(DISTINCT)
SELECT DISTINCT jobTitle FROM employees;
컬럼 별칭(AS)
SELECT orderNo AS 주문번호;
WHERE에서는 별칭을 사용할 수 없음
SELECT orderNo, quantity * priceEach 주문액
FROM orderDetails
WHERE orderNo = 10100 AND 주문액 >= 2000;
SELECT orderNo, quantity * priceEach 주문액
FROM orderDetails
WHERE orderNo = 10100 AND quantity * priceEach >= 2000;
-- quantity * priceEach 연산은 한번 수행
WITH - 자주 사용
WITH temp AS
(
SELECT orderNo, productCode, quantity, priceEach, quantity * priceEach AS 주문액
FROM orderDetails
)
SELECT orderNo, productCode, quantity, priceEach, 주문액
FROM temp
WHERE orderNo = 10100 AND 주문액 >= 2000;
CONCAT
SELECT CONCAT(firstName, ' ', lastName) AS 이름, jobTitle AS 직책
FROM employees
WHERE <> 'Sales Rep';
SELECT name AS 상품명, CONCAT('USD', buytPrice) AS 구매 단가;
CASE
SELECT orderNo, orderDate
CASE status
WHEN 'In Process' THEN '처리중'
WHEN 'Shipped' THEN '배송중'
ELSE '없음'
END AS status
FROM orders
WHERE YEAR(orderDate) = 2005 AND MONTH(orderDate) = 5
SELECT CONCAT(firstName, ' ', lastName) AS 이름,
CASE
WHEN (MONTH(NOW()) > MONTH(birthDate)) OR
(MONTH(NOW()) = MONTH(birthDate)) AND
(DAY(NOW()) = DAY(birthDate))
THEN YEAR(NOW()) - YEAR(birthDate)
ELSE YEAR(NOW()) - YEAR(birthDate) - 1
END AS 만나이
FROM employees;
- 중첩 가능
SEKECT customerId, checkNo, amounnt,
CASE
WHEN amount >= 6000 THEN 'A'
ELSE
(
CASE
WHEN amount >= 4000 THEN 'B'
WHEN amount >= 2000 THEN 'C'
ELSE 'D'
END
)
END AS '지불 규모'
FROM payments
WITH dumy AS
(
SELECT productCode, name, buyPrice, quantityInStock, buyPrice * quantityInStock AS 재고액
FROM s_products
)
SELECT productCode, name, buyPrice, quantityInStock, 재고액,
CASE
WHEN 재고액 >= 500000 THEN 'A'
WHEN 재고액 >= 400000 THEN 'B'
WHEN 재고액 >= 300000 THEN 'C'
ELSE 'D'
END AS 재고등급
FROM dumy
비교 연산자
IN
SELECT productCode, name, vendor, productLine
FROM products
WHERE (vendor, productLine) IN (('AAA', 'BBB'), ('CCCC', 'DDDD));
LIKE
SELECT *
FROM employees
WHERE jobTitle LIKE '%Sales Manager%';
BETWEEN
SELECT *
FROM products
WHERE MSRP BETWEEN 160 AND 180;
SELECT *
FROM products
WHERE vendor BETWEEN 'sa' AND 'sx'
ORDER BY vendor;
vendor BETWEEN 'sa' AND 'sz' 는 vendor LIKE '%s'와 같지 않다
sza를 vendor BETWEEN 'sa' AND 'sz' 는 거르지 못한다
NULL
SELECT *
FROM offices
WHERE state = NULL -- 언제나 FALSE
SELECT *
FROM offices
WHERE state IS NULL -- OK
GROUP BY
SELECT territory, COUNT(*) 지점수
FROM offices
GROUP BY territory;
-GROUP BY 절을 실행하면 그룹핑 기준 컬럼과 집단 함수 기준 컬럼만으로 구성된 임시 테이블(중복 로우 포함)을 메모리에 생성
- 즉 그 이외의 컬럼들은 메모리에서 제거함
- 제거된 컬럼을 SELECT 절에서 사용할 수 없음
집단 함수
GROUP BY 없이 집단 함수 사용
SELECT productCode, COUNT(*) 상품수
FROM products
WHERE productLine IN ('Ships', 'Trains')
GROUP BY 절은 중첩 불가능
SELECT ROUND(AVG(COUNT(*)), 2) '평균 고객수'
FROM customers
GROUP BY country;
GROUP BY가 AVG와 COUNT중 어디에 적용되는지 모호함
정답
WITH temp AS
(
SELECT country 국가, COUNT(*) 고객수
FROM customers
GROUP BY country
)
SELECT ROUND(AVG(고객수), 2) '평균 고객수'
FROM temp;
HAVING
GROUP BY 절로 생성한 그룹 중, HAVING 절의 그룹 조건식을 만족하는 그룹만 선택
WHERE 로우 조건식 : 로우 조건식이 true인 로우만 선택
HAVING 그룹 조건식 : 그룹 조건식이 true인 그룹만 선택
WHERE과 GROUP BY를 잘 사용하여 성능을 높일 수 있다.
- 비 효율적
SELECT productLine 상품라인, COUNT(*) 상품수
FROM products
GROUP BY productLine HAVING productLIne IN ('Ships', 'Trains');
- 더 효율적, WHERE에서 데이터를 간추린 후 GROUP으로 묶음
SELECT productLine 상품라인, COUNT(*) 상품수
FROM products
WHERE productLIne IN ('Ships', 'Trains');
GROUP BY productLIne;
GROUP BY, HAVING 절 조함은 WHERE 절 조합보다 더 느리다 따라서 가능하면 WHERE절로 데이터를 추리는 것을 권고
ORDER BY
SELECT *
FROM employees
WHERE jobTitle <> 'Sales Rep'
ORDER BY 4 DESC, 2
ORDER BY 절에는 SELECT 목록에 나타나지 않은 컬럼이 포함될 수 있음
GROUP BY 절을 같이 사용하면, SELECT 목록에 나타나지 않은 컬럼을 ORDER BY 절에 사용할 수 없음
SELECT vendor
FROM products
GROUP BY vendor
ORDER BY name; //정렬에 영향을 끼치지 않음
// vendor에 대한 그룹 정보만 있고 name은 없기에 name은 있으나 마나이다.
LIMIT
SELECT orderNo
FROM orders
ORDER BY orderDate DESC
LIMIT 10, 5
SELECT 문에서는 정렬을 완료한 후 데이터를 출력하는 것이 아니라, 데이터를 먼저 검색한 후 검색 결과에 대해 정렬 작업을 실행함. 즉 ORDER BY 절은 결과 집합을 결정하는데 관여하지 않음
윈도우 함수를 사용한 Top-N Query 처리
SELECT
ROW_NUMBER() OVER (ORDER BY orderDate DESC) as rowNo,
orderNo, orderDate
RANK() OVER (ORDER BY orderDate DESC) AS dateRank
FROM orders;
WITH temp AS
(
SELECT ROW_NUMBER() OVER (ORDER BY order Date DESC) as rowNo,
orderNo, orderDate, status, customerId
FROM orders
)
SELECT rowNo, orderNo, orderDate, status, customerId
FROM temp
WHERE rowNo BETWEEEN 40 AND 44