[MS-SQL] 집계함수(count, sum, avg, min, max), Group by, Having, Compute, Datetime

■ select 구문의실행순서

 select  컬럼명  -- 5
 from    테이블명-- 1
 where   조건절  -- 2
 group by    절  -- 3
 having      절  -- 4
 order by    절  -- 6

■ 집계함수 count(), sum(), avg(), min(), max()

● count()

/*
count() 함수- 수를세아리다
: 현재select 에의해서반환되고있는레코드(컬럼)의갯수를반환
문법: count(컬럼명)
*/

-- 서울에사는회원은몇명??
select COUNT(*) from userTbl where addr = '서울'; 

-- 아시아와유럽에속한나라의갯수?? 7개
select COUNT(*) from tblCountry where cont in ('AS','EU'); -- or 조건

-- count() 함수의인자값이(*) 이거나(컬럼명) 일떄의차이점
select COUNT(*) from tblgroup; -- 직원수25명
select COUNT(name) from tblGroup; -- 직원의이름이총25개인상황
select COUNT(achieve) from tblGroup; -- 인자값으로컬럼명을줬을때!!!
-- null값은카운트에서제외(***)

-- 실적보너스1,000,000 원-> 1/n 분배
select 10000000 / 25; -- (X)
select 10000000 / COUNT(*) from tblGroup; -- (O) 모든직원에게분배
select 10000000 / COUNT(achieve) from tblGroup; -- 실적null 인사람뺴고분배

-- 실적이있는사원수?
select COUNT(achieve) from tblGroup; 

-- 실적이없는사원수?
select COUNT(*) - COUNT(achieve) from tblGroup; 
select COUNT(*) from tblGroup where achieve is null 

-- 근무개월수가1년이상2년이하인직원수?
select COUNT(workmonth) from tblGroup where workMonth between 12 and 24

--중복값제거
select distinct(cont) from tblCountry; 
select count(distinct(cont)) from tblcountry;

● sum()

/*
sum()함수
문법: sum(컬럼명)
컬럼값의총합을반환
*/

select achieve from tblGroup; -- 개인별실적
select SUM(achieve) from tblGroup; -- 총합실적

--Error
select SUM(name) from tblGroup; -- 컬럼(name)이 숫자가 아닐경우는 에러가 난다.

● avg()

/*
avg() 함수
문법: avg(컬럼명)
: 컬럼값의평균을반환하는함수
: null 레코드는제외!!!! (count() 와같다.)
*/

select AVG(achieve) from tblGroup; -- 개인당평균
select avg(workmonth) from tblGroup;
select sum(achieve) as [총실적수], avg(achieve) as [평균실적수] from tblGroup;

● min(), max()

/*
max(컬럼명) 함수: 최대값
- 컬럼명중최대값하나를반환시킨다.
min(컬럼명) 함수: 최소값
- 컬럼명중최소값하나를반환시킨다.
문자형역시산출가능
*/

-- 월급이가장많은액수?
select COUNT(salary) from tblGroup;
select SUM(salary) from tblGroup;
select MAX(salary) from tblGroup;
select MIN(salary) from tblGroup;

-- 에러! 집계함수는where절에못쓴다.
select name from tblGroup where salary = MAX(salary);

select MAX(name) from tblGroup; -- 가능
select MIN(name) from tblGroup; -- 가능

■ group by

/*
- group by (그룹을묶어서무언가할수있는일을실행하겠다?)
- 특정컬럼값이동일한레코드의통계값반환
- 집계함수와같이사용함(***) -> 직계함수의결과를그룹지어서보자
- group by를이용해서select 실행시결과리스트안에는...
1. 집계함수
2. group by의대상컬럼이올수있다.
*/

-- 전직원의평균근무개월수? -> AVG()
select AVG(workmonth) from tblGroup; 

-- 부서별직원의평균근무개월? -> AVG() + 조건
select distinct(depart) from tblGroup; -- 관리부, 생산부, 영업부, 지원부
select AVG(workmonth) from tblGroup where depart = '관리부'; 
select AVG(workmonth) from tblGroup where depart = '생산부'; 
select AVG(workmonth) from tblGroup where depart = '영업부'; 
select AVG(workmonth) from tblGroup where depart = '지원부'; 

-- depart 컬럼값이동일한값을갖는레코드끼리묶자!!(그룹화)
select AVG(workmonth) as [근무개월], depart from tblGroup group by depart;

-- 에러구문,
select workmonth from tblGroup group by depart; 
-- group by depart로 부서를 묶었는데 거기서 workmonth를 가져오라고 하니
-- 근무개월수가 부서별 개인마다 다 다른데 어떤걸불러와야 할지모른다.
-- 그러므로 집계함수나 대상컬럼외에는올수없다.

-- 각부서별직원수?
select depart, COUNT(*)as[부서별직원] from tblGroup group by depart;

-- 각부서별최대월급은?
select depart, MAX(salary) as [부서별월급] from tblGroup group by depart;

-- 대륙별국가수?
select cont, COUNT(*) from tblCountry group by cont;

-- 사용자아이디별로물품에상관없이총구매갯수?
select userid, sum(amount) from buyTbl group by userid;

-- 사용자아이디별로물품에상관없이총구매액수?
select userid, SUM(price * amount) from buyTbl group by userid;

-- 분야별(type) 도서의평균가격?, 도서몇권?, 가장비싼책가격?, 가장싼책가격?
select [TYPE], AVG(price) as [평균가격], COUNT(type)as [도서몇권], MAX(price)as [비싼책], MIN(price) as [싼책] from titles group by [type];

■ having

/*
- having
: group by 의조건절역할
*/

--각부서별평균월급?
select depart, AVG(salary) from tblgroup group by depart;

-- 각부서별평균월급이180만원이상인부서를나타내시오
select depart, AVG(salary) from tblgroup group by depart having AVG(salary) > 180;

-- 각부서별평균월급이180만원이상인부서를나타내고, 평균월급정렬
select depart, AVG(salary) from tblgroup group by depart having AVG(salary) > 180
order by AVG(salary) desc;

--(가장우선하는전제조건) 12개월근무가넘은사람들에한해서..
-- 평균월급180만원이상인부서별평균월급? 평균월급정렬
select depart, avg(salary) as [월급] from tblgroup where workmonth >= 12 group by depart
having avg(salary) > 180 order by avg(salary) desc;

-- 위의select와차이점이해!!
select depart, avg(salary) as [월급] from tblgroup group by depart having avg(salary) >180
and AVG(workmonth) >= 12 order by avg(salary) desc;

-- 관리부, 생산부대상-> 부서별평균월급
select depart, AVG(salary) from tblGroup group by depart
having depart = '관리부' or depart = '생산부'; -- 비추천

select depart, AVG(salary) from tblGroup group by depart
having depart in('관리부','생산부'); -- 추천구문(0)

■ compute

/*
- compute ( 사용도떨어짐^.* )
: select 실행후별도의집계결과를반환
: 집계함수과같이사용
: select의대상은집계함수
*/

select * from tblGroup;
select AVG(salary) from tblGroup; -- 전체직원의평균월급

select * from tblGroup compute avg(salary); -- 위의두문장을한문장으로표현

-- 일이끝나고난뒤별도의집계합수값을실행()
select * from tblGroup compute sum(salary); -- tblgroup을다가져온뒤월급총합을보여준다.

■ Datetime 함수

/*
- 날짜시간함수
: Datetime 형
*/

select GETDATE() as [현재시간];

create table tblMemo
(
    seq int identity(1,1) primary key, -- 메모번호
    memo nvarchar(1000) not null, -- 메모내용
    writedate datetime not null -- 작성시간
)

insert into tblMemo (memo,writedate)
values('메모입니다.~', GETDATE()); -- getdate() 직접입력

select * from tblMemo

create table tblMemo2
(
    seq int identity(1,1) primary key, -- 메모번호
    memo nvarchar(1000) not null, -- 메모내용
    writedate datetime default(getdate()) not null -- 작성시간
)

insert into tblMemo2(memo) values('메모입력했다잉~'); -- gatdate() 기본값으로자동입력

select * from tblMemo2;

insert into tblMemo2(memo) values('메모다잉~'); -- 시간을 두고 F5 입력 ↓
insert into tblMemo2(memo) values('메모다잉~1');
insert into tblMemo2(memo) values('메모다잉~2');
insert into tblMemo2(memo) values('메모다잉~3');
insert into tblMemo2(memo) values('메모다잉~4');
insert into tblMemo2(memo) values('메모다잉~5');

select writedate from tblmemo2;

-- 가장최근에쓴메모가언제쓴메모??
select top 1 writedate from tblMemo2 order by writedate desc;

select MAX(writedate) from tblmemo2; -- 위아래같은구문

■ 추출 DatePart

/*
- 추출(년,월,일)
DatePart(year,month,day)
*/

select DATEPART(YEAR, max(writedate)) from tblMemo2;
select DATEPART(MONTH, max(writedate)) from tblMemo2;
select DATEPART(DAY, max(writedate)) from tblMemo2;
select DATEPART(HOUR, max(writedate)) from tblMemo2;
select DATEPART(MINUTE, max(writedate)) from tblMemo2;
select DATEPART(SECOND, max(writedate)) from tblMemo2;
select DATEPART(YEAR, DAY(writedate)), writedate from tblMemo2;

-- 6월에출간된도서명?
select * from titles;
select * from titles where DATEPART(MONTH, pubdate) = 6;
select DATEPART(MONTH,pubdate) from titles; -- 출간일의그달만표시

-- 2000년이후출간도서? 2건
select * from titles where pubdate > '2000-01-01';

■ datetime 연산

/*
- datetime 연산
DATEADD(형식,시간,시각) return 시각: 시각+ 시간= 시각
DATEDIFF(형식,시간,시각) return 시간: 시각- 시각= 시간
*/

select * from tblMemo2;

-- 메모시간+ 100일
select writedate, DATEADD(DAY,100,writedate) from tblMemo2; -- DAY + 100일= writedate에적용

-- 메모시간- 100일
select writedate, DATEADD(DAY,-100,Writedate) from tblMemo2;

-- 메모시간+ 100년
select writedate, DATEADD(YEAR,100,Writedate) from tblMemo2;

-- 메모를각각적은후얼마나지났는지
-- 원하는건: 현재시각- 기록시각= 시간
select writedate from tblMemo2;
select writedate, DATEDIFF(HOUR, writedate, GETDATE()) from tblMemo2;

-- DATEDIFF(HOUR,기록시간,현재시간()) : 기록시간- 현재시간을시간으로나타낸다.
select writedate from tblMemo2;
select LEFT(writedate,4) from tblMemo2;