기초 SQL 학습 3일차
❇️ 오늘 배운 내용
1. 날짜 연산, case 조건문, 정렬과 연산 함수 몇 개
2. 행 수정 삭제 추가
3. 집계와 서브쿼리
주요 개념
CURRENT_TIMESTAMP
Trim | substring | concat | coalesce | null | round |
datediff | date_add | date_sub | interval |
case, when, then, else, end / as
오전 강의
| SQL 기본 문법 - 날짜, 조건문, 정렬
- SELECT CURRENT_TIMESTAMP 시스템 현재 시각
- TIMEDIFF, date_add, date_sub 으로 날짜 계산하기 : date_add(now(), interval 1 day)
- concat 문자열 합치기, trim 공백 제거, round 반올림, substring 일부 문자열 추출
- 조건식 case문(select, where, order by에 사용) : case, when, then, else, end, as
- case문으로 null 구하는 방법, COALESCE로도 null 바꿔주기
- 환경 설정 주의해
이거 새 편집기 열면 꼭 체크하셈 그래야
이런 게 뜸.
이거 안하면 약어도 안뜸.
이래도 검색됨 편리함 대박 ㄷ ㄷ
비슷한 테이블명이 끝 번호로 구분될 때 유용함.
- concat 문자열 합치기, trim 공백 제거, round 반올림, substring 일부 문자열 추출
concat: 문자열 인수 합쳐주는.
select concat(quantity, unit) as 합치기 from sample35;
trim : 스페이스 외 문자도 여기선 제거할 수 있음.
(엑셀이나 파이썬에선 안될걸)
round: 소수점 올려줌. 기본적으로 0이고, 몇자리 수까지는 남기고 싶다 하면 넣으면 됨.
59.65234면
round(ㅇㅇ, 2) → 59.65
round(ㅇㅇ, 1) → 59.7
round(ㅇㅇ) → 60
59.9522면
round(ㅇㅇ, 2) → 59.95
round(ㅇㅇ, 1) → 60.0
round(ㅇㅇ) → 60
substring: 앞의 숫자 몇 개 빼주는 거.
중간에 숫자든 글자든 상관없음.
select substring(상품명, 3, 1) as 상품넘버 from 상품2;
SUBSTRING 함수를 사용하여 일부 문자열을 반환 할 수 있습니다.
where 에 다는 like 술어는 일부 문자열로 검색하는 거고 ㅇㅇ
반환과 검색의 차이.
( Column명, 출력하고싶은 첫번째 자리수, 출력할 문자의 개수)
주로 날짜 연산에서 많이 사용됨
@ concat
select * from sample35;
select concat(quantity, unit) from sample35;
select concat(quantity, unit) as 합치기 from sample35;
@ substring
select * from 상품2;
select substring(상품명, 3, 1) as 상품넘버 from 상품2;
/* 실습 */
select * from track t;
-- 문제 1 --
-- 왜 공백 제거 안된 거 같지?
select trim(Name) from track t
where Name like "The%" ;
-- 이거의 또 하나 문제는 " the" 인걸 못가져온단 거임. the 앞에 공백이 있는 걸 못가져옴.
-- 이거량 위랑 결과 똑같음
select Name from track t
where Name like "The%" ;
-- 디요옹... 셀렉트에서 트림으로 새 열을 임시로 만든 건데 원본인 네임에서 추출해서 그런 거였음. 엥 근데 똑같다?
-- 혹시 맨앞에 공백이 원래 몇개 없어서 그런가?
select trim(Name) from track t
where trim(Name) like "The%" ;
select Name, trim(Name) from track t
where trim(Name) like "The%" ;
select trim(Name) from track t;
-- 엥 검색 안되는데
select Name from track t
where Name like " the%" ;
-- 이것도...
select Name from track t
where Name like " %" ;
-- 연습문제 2 --
select concat(Name, GenreId) as "트랙명 (장르 ID)" from track t ;
-- 위에 거 맞긴 한데 사이에 공백 넣어주셈.
select concat(Name, " ~ ", GenreId) as "트랙명 (장르 ID)" from track t ;
-- 깔끔한 방법은 이거
select concat(Name, " (", GenreId, ")" ) as "트랙명 (장르 ID)" from track t ;
-- 문 3 --
select substring(Name, 1, 5) from track t ;
-- 조건에 응용하기
select * from track t
where name = substring(Name, 1, 5) ;
/* 2일차 교안 끝 */
내가 트림을 이미 실행을 해놔서 공백이 없어진 상태로 검색하고 트림 또 실행해서
그래서 트림이 안보인 것인가
그렇다기에는 셀렉트 하고 원래대로 뽑으면 보여야 하지 않나?
셀렉트는 원본에 영향을 못끼치니까?
아님 공백이 제거된 건데 내 눈에 띄워져 보엿을 뿐인가
그냥 열과 열 사이의 당연한 간격이었을 뿐인가?
날짜 타입, 날짜 연산
SELECT CURRENT_TIMESTAMP
- 현재 시각 구하기
SELECT CURRENT_TIMESTAMP ;
select current_date ;
select current_time ;
-- [ 날짜 타입 ] --
-- 현재 시스템 시각 불러오기. date 타입이고 밑에 둘다 됨.
-- from 생략 안하면 그 테이블의 행 갯수만큼 반복 출력됨.
select current_timestamp();
select current_timestamp;
-- 이건 안됨
select current;
-- 자동완성 하면 ()가 자동 생기는데 비우고 하면 걍 행이름만 그럴 뿐 결과는 똑같음.
-- date는 날짜만, time은 시간만
select current_date() ;
select current_date ;
select current_time() ;
select current_time ;
* 현재 시각을 뽑는 함수인데 () 안에 뭘 넣을 수 있단 말인가...?
- 날짜를 빼는 방법 ( 날짜 간 간격 구하기 )
date_sub
: 날짜 빼기
DATEDIFF(‘ 날짜1’, ‘날짜2’)
TIMEDIFF
select datediff('2024-07-08', '2024-07-20');
- 날짜를 더하는 방법
1. current_date + interval 1 day
2. date_add(now(), interval 1 day)
3. adddate(now(), interval 1 day)
-- [ 날짜 연산 ] --
-- x
select current_date(month);
-- o
select current_date + interval 3 day;
select current_date - interval 3 day;
select current_date + interval 3 month;
select adddate(now(), interval 1 day) ;
select date_add(now(), interval 1 day) ;
select date_sub(now(), interval 1 year) ;
select date_add(now(), interval 1 year), date_sub(now(), interval 1 year) ;
-- 두 구간 사이의 일수 구하기 : 각각 3, -3으로 나옴
select datediff(current_date(), current_date() - interval 3 day);
select datediff(current_date() - interval 3 day, current_date());
-- 날짜에 '' 안치면 오류임. 안에 - 안넣어도 오류인가 ? 이건 -12로 나옴
select datediff('2024-07-08', '2024-07-20');
* date_add와 adddate 차이??
* date_sub과 datediff 차이??
* interval이 뭘가, 아 간격이란 뜻이네. 필수인가 add 함수인데?
- 데이터 타입 주의!
text라 되어 있으면 date 계산 함수를 못씀.
그러니 먼저 바꾸고 시작 ㄱㄱ
아니면 이거 입력.
ALTER TABLE seongdong.Invoice MODIFY COLUMN InvoiceDate DATETIME NOT NULL;
SQL에서 IF 하기 - CASE 문
파이썬에선 IF (반복문은 FOR, WHILE)
엑셀에서 if문 case문 둘다 있는 거 같은데?
CASE WHEN 조건식1 THEN 1 [ WHEN 조건식2 THEN 식2 …] [ ELSE 식3] END
ELSE를 생략한 경우, ‘ELSE NULL’로 간주됩니다.
CASE문은 WHERE 이나 ORDER BY 구에서도 사용 가능.
- case 함수로 null값을 0으로 바꿔주는 예시 구문
null은 원래 집계 안되는데 그래도 집계하고 싶을 때 0으로 바꿔서 세달라고 하는 코드로, 자주 쓰는 거임.
select a(원본 열 이름),
case
when a(열 이름) is null(null이라면)
then 0 (0으로 처리하고)
else a (그게 아니면 a를 그대로 뽑아주는 열을 만들어라.)
end as (별명은) "a(null=0)" ("a(null=0)"로 붙여라.)
from sample37; (37번 테이블에서 뽑아서)
= '샘플37'이라는 이름의 테이블에서, a라는 열을 출력하고, a에서 공백인 부분을 0으로 바꿔주고 나머지는 그대로 두는 열도 하나 만들어서 출력해라.
- null을 좀더 쉽게 구하기: coalesce(인자1, 인자2, ...)
더 간단하게는 이렇게 쓸 수 있다. coalesce(열 이름, 바꿀 내용)
COALESCE는 인자로 주어진 컬럼들 중 NULL이 아닌 경우의 값을 리턴한다.
select a, coalesce(a, 0) from sample37 s ;
coalesce(a, 0)를 예로 들 때
a열의 1행이 null이 아니면 a열의 1행을 그대로 출력하고, null이면 0을 출력하라.
이걸 쭉 반복함.
파이썬의 np.where로 null 값 찾는 방식이랑 비슷함.
-- [ 조건식 case ] --
select * from sample37 s ;
-- case로 null값을 0으로 바꿔주기
select a,
case
when a is null then 0
else a
end as "a(null=0)"
from sample37 s ;
select a, coalesce(a, 0) from sample37 s ;
-- 실습
-- x
select a,
case
when a is null then '미지정'
elseif a = 1 then '남자'
elseif a = 2 then '여자'
else
end
from sample37 s ;
-- elseif 안씀, else에 뭐 되는지 붙여야 함. (파이썬 if문이 elif임)
-- 고쳐봄. 이제 됨.
select a,
case
when a is null then '미지정'
when a = 1 then '남자'
when a = 2 then '여자'
else a
end
from sample37 s ;
-- end 옆에 as 해서 이름 붙여주는 이유... 열 이름이 'case when... end'로 터무니없이 길어져서.
-- ㅇ
select a,
case
when a = 1 then '남자'
when a = 2 then '여자'
else '미지정'
end
from sample37 s ;
select a,
case
when a = 1 then '남자'
when a = 2 then '여자'
when a is null then '미지정'
else a
end
from sample37 s ;
select a,
case a
when 1 then '남자'
when 2 then '여자'
else '미지정'
end as "성별"
from sample37 s ;
무시무시한 실습 문제
-- [ 연습 문제 ] --
-- 섭스트링으로 풀 수 있대
select InvoiceId , InvoiceDate , year(InvoiceDate) as "주문 년도"
from invoice i ;
-- x 왜 안됏냐면 함수 넣은 수식의 경우 전체를 다 써야 하기 때문. 공식문서에 나와있음
select InvoiceId , InvoiceDate , year(InvoiceDate) as "주문 년도",
case year(InvoiceDate)
when = 2007 then "2007년 데이터"
when = 2009 then "2009년 데이터"
when > 2009 then "2009년 이후 데이터"
else is null
end as "데이터 분류"
from invoice i ;
select InvoiceId , InvoiceDate , year(InvoiceDate) as "주문 년도",
case year(InvoiceDate)
when year(InvoiceDate) = 2007 then "2007년 데이터"
when year(InvoiceDate) = 2009 then "2009년 데이터"
when year(InvoiceDate) > 2009 then "2009년 이후 데이터"
else year(InvoiceDate) is null
end as "데이터 분류"
from invoice i ;
-- 이건 다 0으로 뜸 땀땀
select InvoiceId , InvoiceDate , year(InvoiceDate) as "주문 년도",
case year(InvoiceDate) as y
when y = 2007 then "2007년 데이터"
when y = 2009 then "2009년 데이터"
when y > 2009 then "2009년 이후 데이터"
else y is null
end as "데이터 분류"
from invoice i ;
select InvoiceId , InvoiceDate , year(InvoiceDate) as "주문 년도",
case year(InvoiceDate)
when 2007 then "2007년 데이터"
when 2009 then "2009년 데이터"
when > 2009 then "2009년 이후 데이터"
else is null
end as "데이터 분류"
from invoice i ;
-- o
select InvoiceId , InvoiceDate , year(InvoiceDate) as "주문 년도",
case
when year(InvoiceDate) = 2007 then "2007년 데이터"
when year(InvoiceDate) = 2009 then "2009년 데이터"
when year(InvoiceDate) > 2009 then "2009년 이후 데이터"
else year(InvoiceDate) is null
end as "데이터 분류"
from invoice i ;
-- 강사님 풀이
select InvoiceId , InvoiceDate , substring(InvoiceDate, 1, 4) as "주문 년도",
case
when substring(InvoiceDate, 1, 4) = 2007 then "2007년 데이터"
when substring(InvoiceDate, 1, 4) = 2008 then "2008년 데이터"
when substring(InvoiceDate, 1, 4) = 2009 then "2009년 데이터"
else "2009년 이후 데이터"
end as "데이터 분류"
from invoice i ;
select InvoiceId , InvoiceDate , substring(InvoiceDate, 1, 4) as "주문 년도",
concat(substring(InvoiceDate, 1, 4), "년 데이터") as "데이터 분류"
from invoice i ;
-- 내가 해보는 거
select InvoiceId , InvoiceDate , substring(InvoiceDate, 1, 4) as "주문 년도",
case
when year(InvoiceDate) < 2010
then concat(substring(InvoiceDate, 1, 4), "년 데이터")
else "2009년 이후 데이터"
end as "데이터 분류"
from invoice i ;
-- 2번 문제 --
date_format() 어케 씀
day() 하면 걍 날짜가 1 14 이케만 나옴
current_date(InvoiceDate) 당연히 안됨
select date(InvoiceDate) as "주문 일자"
from invoice i ;
-- 이거 왜 틀렷냐면 from 뒤에 가야 해서 ㅎ
select DATE(InvoiceDate) as "주문 일자", datediff('2011-12-31', InvoiceDate) as "폐업 며칠 전 주문인가",
case
when datediff('2011-12-31', InvoiceDate) < 366 then "1년 이내"
when datediff('2011-12-31', InvoiceDate) < 366*2-1 then "2년 이내"
when datediff('2011-12-31', InvoiceDate) < 366*3-2 then "3년 이내"
else '오래 됨 ㄷ ㄷ ㄷ'
end as "경과 기간"
where order by datediff('2011-12-31', InvoiceDate) desc
from invoice i ;
-- ㅇ
select DATE(InvoiceDate) as "주문 일자", datediff('2011-12-31', InvoiceDate) as "폐업 전 얼마나 오래 된 주문인가",
case
when datediff('2011-12-31', InvoiceDate) < 366 then "1년 이내"
when datediff('2011-12-31', InvoiceDate) < 366*2-1 then "2년 이내"
when datediff('2011-12-31', InvoiceDate) < 366*3-2 then "3년 이내"
else '오래 됨 ㄷ ㄷ ㄷ'
end as "경과 기간"
from invoice i
order by datediff('2011-12-31', InvoiceDate) ;
-- 이거 하면 9부터 낮은 수부터 정렬되는데 별명으로 정렬하면 큰수가 나옴. 영어로 정렬해도 마찬가지임.
select DATE(InvoiceDate) as "주문 일자", datediff('2011-12-31', InvoiceDate) as "폐업 전 얼마나 오래 된 주문인가",
case
when datediff('2011-12-31', InvoiceDate) < 366 then "1년 이내"
when datediff('2011-12-31', InvoiceDate) < 366*2-1 then "2년 이내"
when datediff('2011-12-31', InvoiceDate) < 366*3-2 then "3년 이내"
else '오래 됨 ㄷ ㄷ ㄷ'
end as "경과 기간"
from invoice i
order by InvoiceDate desc ;
-- 이건 내가 풀어본 건데 정리안함 아직...
핵심 풀이만 보기
Q1. Invoice 테이블을 사용하여 각 주문의 InvoiceDate를 기준으로 분류하여
InvoiceID와 InvoceDate, 주문 년도 를 출력하세요.
( 2007년 데이터, 2009년 데이터, 2009년 이후 데이터 로 분류)
select invoiceid, InvoiceDate,substring(InvoiceDate, 1, 4)
CASE substring(InvoiceDate, 1, 4)
WHEN '2007' THEN "2007년 데이터"
WHEN '2008' THEN "2008년 데이터"
WHEN '2009' THEN "2009년 데이터"
ELSE "2009년 이후 데이터"
END
from Invoice i ;
select invoiceid, InvoiceDate,
concat(substring(InvoiceDate, 1, 4), "년도 데이터")
from Invoice i ;
-----
Q2.011-12-31까지의 경과일을 계산하고, 경과 기간을 분류하세요
(ex: 1년 이내, 2년 이내, 3년 이내 )
select DATE(InvoiceDate) as "주문 일자",
datediff('2011-12-31', InvoiceDate) as "HOWLONG",
case
when datediff('2011-12-31', InvoiceDate) < 366 then "1년 이내"
when datediff('2011-12-31', InvoiceDate) < 366*2-1 then "2년 이내"
when datediff('2011-12-31', InvoiceDate) < 366*3-2 then "3년 이내"
else '오래 됨 ㄷ ㄷ ㄷ'
end as "경과 기간"
from invoice i
order by datediff('2011-12-31', InvoiceDate) ASC;
-----
아까 강사님이 알려주셨던... 섭 스트링 써서 하는 법에서
case 써서 나머지 부분을 그룹화하는 방법 (내가 해봄)
select InvoiceId , InvoiceDate , substring(InvoiceDate, 1, 4) as "주문 년도",
case
when year(InvoiceDate) < 2010
then concat(substring(InvoiceDate, 1, 4), "년 데이터")
else "2009년 이후 데이터"
end as "데이터 분류"
from invoice i ;
오후 강의
| 소제목
데이터 추가 insert into .. values() / 삭제 delete from ... where / 수정 UPDATE .. set ㅇ = ㅇㅇ
약
- 데이터 추가 insert into .. values()
insert into 테이블명
values (행만큼의 인자를 넣기)
values (여러 행 넣을 땐 이렇게)
values (행만큼의 인자를 넣기);
근데 이거 되는 거 맞음? 확인해보자
나 왜 오류났던 거냐
INSERT INTO 테이블명 VALUES (값 1, 값2, …)
- 삭제 delete from ... where ..
- 수정 UPDATE .. set ㅇ = ㅇㅇ
전 직원 연봉 퍼센트 똑같이 인상할 때 유용함.
예시에서 no = no + 1은 varchar 타입을 int 타입으로 바꾼 걸거임.
안바꾸고 하면 안먹힐 가능성 높음.
데이터 날려먹지 않게 매우 주의하라.
일부 행만 바꾸고 싶으면 꼭 웨얼문 써라.
< 같은 팀 엘리트분이 아지트에 올려주신 실습문제 풀이법 >
-- 연습문제 q1
select name,trim(name) from track t
where trim(name) like 'the%';
-- 연습문제 q2
select name, genreid, concat(name," ", genreid) from track t ;
-- 연습문제 q3
select substring(name,1,5)as name5 from track t;
- 프로덕트 선정
명령어 실행할 때 데이터 날라갈깝화 컴이 경고해주는 게 잇는데 그거 꼭 잘보셈 꼭꼭
백업데이터도 중요함
벨류스로 할때도 지정 가능한지
벨류로 할 때도 여러개 지정 가능한지
둘다 예약어
왜 is null이 아니라 = null인지 알려주셨는데
비교연산자 어쩌고 하셨는데 이해못했음.
< 같은 팀 엘리트분이 아지트에 올려주신 실습문제 풀이법 >
update employee set phone = concat('+',phone)
where phone not like '+%';
-- q2
insert into employee (EmployeeId, LastName, FirstName)
values (9, 'john','doe');
select * from employee e
-- q3
update employee set title='Data Analyst'
where EmployeeId = 9;
select * from employee e
-< 내가 쓴 풀이법이랑 똑같아서 내 거는 생략하고 이것만 백업 >-
< insert, delete, update 실습 답안 >
-- 강사님이 아지트에 올려주신 풀이법 --
select * from employee;
update Employee
set Fax = concat("+" , fax)
where fax like "1%"
insert into employee values (10, "john", "doe",null,null,null,null,null,null,null,null,null,null,null,null);
INSERT INTO employee (EmployeeId , lastName, firstName)
VALUES (9, "john", "doe");
update Employee set title='General Manager'
where LastName="john" AND firstName="doe"
UPDATE employee
SET Phone =
CASE
WHEN Phone NOT LIKE '+1%' THEN CONCAT('+', Phone)
ELSE Phone
END
WHERE phone LIKE "1%";
근데 마지막에 case 쓰는 거 이름 안바뀌지? end as로 별명 붙일 필요 없지?
셀렉트에서 달 때나 열이 임시로 생기는건데
업데이트는 정해진 열에
ㅀㅎ
*는 애스터 리스크
집계와 서브쿼리
count 함수
-- NULL 값 빼고 계산하니까 둘다 다르게 나옴.
select count(no), count(name) from sample51 s ;
그럼 NULL 포함 전체줄이 몇갠지 알려면 NULL이 없는 열을 검색한 다음에 카운트 해야 하나?
→ NONO 걍 COUNT(*) 하면 됨.
→ 만약 모든 열이 NULL인 행이 있다면? 그것도 무시안함? 애초에 그런 줄이 있을 수 있음?
그런줄이 있으면 각 열로 카운트하면 4개 되는데 전체 카운트하면 5 나옴?
ALTER TABLE seongdong.sample41 MODIFY COLUMN a varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci DEFAULT '404 not found' NULL;
나의 질문
테이블에 최소 열은 1개 있어야 하는데 행은 0이어도 성립됨
그럼 그 경우 COUNT(*) 하면 0 나오냐 NULL 나오냐
0 나옴
셀수 있어서.
행이 있긴 한데 모든 열에서 NULL이야
그럼 1 나옴 행이 있긴 하니까 ㅇㅇ
만약 열 3개 행 3개인 데이터가 있어
마지막 행은 열 3개가 전부 NULL이야
그럼 열1 열2 열3 뭘 카운트하든 2만 나옴
하지만 카운트(*) 하면 다 세줘서 3 나옴
즉 열을 딱 지정했을 때만 그 열에서 NULL을 뺀 걸 구해줘서임.
다른 이 질문
COUNT(ㅇ)
WHERE ㅇ IS NULL
하면 안나옴
셀렉트 해서 NULL 값 찾은 다음 더하는 그런 걸로 해야 ....
< 같은 팀 엘리트분이 아지트에 올려주신 질문에 대한 추가 풀이법 >
sample51에서
name이 null값인거 수량 확인하려면
select count(*) from sample51 s
where name is null;
이런식으로 count * 하고서 name 에 null로 조건걸면 나오는 것 같아요.
< 내가 찾은 추가 풀이법 >
select count(*) - count(name) from sample51 s;
| 집계와 서브쿼리
요약 생략?
- 프로덕트 선정
맥시멈 미니멈은 날짜 타입에도 쓸 수 있긴 함. 가끔 쓰임.
데이터 타입도 수치형이긴 한...
- 프로덕트 선정
소수점 떼는 거 라운드
엑셀도 마찬가지
파이썬은 int로 바꿈.
쿼리 다 쓰고 실행하지 말고 한단계씩 하면서 풀어야 오류 잡기 쉬움.
- 프로덕트 선정
그룹 바이 집계랑 같이 쓰면 유용성이 넘쳐난다.
이렇게 하는 방식
파이썬에선 뭐드라 agg 였나
select count(name), sum(quantity)
from sample51 ;
이름 열이랑
select name, count(name), sum(quantity)
from sample51 s
group by name ;
select name, count(name), sum(quantity)
from sample51 ;
이건 틀림
- 프로덕트 선정
여담
MySQL :: MySQL 8.4 Reference Manual :: 15.2.13 SELECT Statement
-- 탭 인설트, | |
쉬프트 인서ㄹ트 |
* 현재 시각을 뽑는 함수인데 () 안에 뭘 넣을 수 있단 말인가...?
* date_add와 adddate 차이??
[회고]
#청년취업사관학교 #데이터분석가 #데이터분석가부트캠프 #DA교육 #데이터분석교육 #실무프로젝트 #실무경험 #취업포트폴리오 #포트폴리오 #취업연계교육 #코멘토 #모비니티
'새싹 데이터 분석 교육 (24.05.13~24.08.16) > TIL' 카테고리의 다른 글
[성동2기 전Z전능 데이터 분석가] 0710 (0) | 2024.07.10 |
---|---|
[성동2기 전Z전능 데이터 분석가] 0709 (1) | 2024.07.09 |
[성동2기 전Z전능 데이터 분석가] 0705 (미완) (0) | 2024.07.08 |
[성동2기 전Z전능 데이터 분석가] 0704 (미완) (0) | 2024.07.08 |
[성동2기 전Z전능 데이터 분석가] 0624 (0) | 2024.06.24 |