TigerCow.Door

안녕하세요. 문범우입니다.

오랜만에 파이썬으로 필요한 프로그램을 만들어 공유하려고 글 작성합니다.

소개해드리고자 하는 프로그램은


중고나라에서 키워드 검색후 게시글 크롤링 및 메일 발송

기능을 가진 프로그램입니다.


모든 소스코드는 아래의 github주소에 공개되어있습니다.

https://github.com/doorBW/joonggonara_crawl


간단하게 활용 스택 및 배운점 등을 공유하겠습니다.


1. 활용 스택


- Python 3.7.1

- pyenv 및 virtualenv를 통한 가상환경설정

- Selenium / BeautifulSoup / smtplib / dotenv 라이브러리 활용

- ubuntu crontab 활용


위와 같은 언어 및 라이브러리를 활용하였습니다.

crawl.py 에서 중고나라 사이트에 접속하여 사전에 설정해놓은 키워드로 검색을 하고

50개씩 보기를 선택한 후에 중복 글쓴이를 제외한 나머지 게시글을 리스트로 만들어서 메일로 발송합니다.

해당 파일은 aws의 개인서버에 두고 crontab을 활용하여 정해진 시각에 실행되도록 설정하였습니다.



2. 배운 점


과거에 selenium을 활용해본적은 있으나, 이번에 보다 많이 활용해본 것 같습니다.

네이버 카페에서 게시글이 나오는 쪽이 iframe으로 설정되어 있어 selenium에서 frame도 바꿔주어야 했고,

50개씩 보기를 선택하면서 보다 활용도가 높았던 것 같습니다.

활용할수록 매우 재미있는 라이브러리 같아서, 여름쯤 시간내서 한번 더 깊게 공부해보면 재미있을 것 같습니다.

관련되서 재밌는 프로젝트들에 대해서 아시는게 있다면 알려주세요 :)

이 외에 다른 라이브러리나 ubuntu crontab 활용에 대해서는 과거에 사용해봤던 것과 동일했기 때문에 따로 언급하지 않겠습니다.



3. 더 공부해볼 점


사실상 게시글 제목을 중심으로 크롤링을 진행했지만, 그러한 제목에는 상품의 가격이 제대로 나와있지 않습니다.

가격 또한 쉽게 보려면 게시글에 들어가서 내용을 검토해야 하는데, 그렇게 하지 않은 이유는 게시글 내용에서도 가격이 정확하게 나와 있지 않기 때문입니다.

중고나라에서 가격을 적는 칸이 있지만, 사실 대다수가 지키지 않고 있는 실정입니다.

이에 따라서 게시글 내용을 text로 반환 받아 그 내용 중 상품 가격을 추출할 수 있다면 매우 활용적일 수 있습니다.

인공지능 분야에서도 자연어처리 분야에 대해 지식이 필요할 것 같은데, 혹시 관련되서 내용을 아시거나, 다른 방법으로 해당 문제를 해결할 수 있는 방안에 대해서 아신다면 댓글 부탁드립니다!


블로그 이미지

Tigercow.Door

Web Programming / Back-end / Database / AI / Algorithm / DeepLearning / etc


안녕하세요. 문범우입니다.

이번 포스팅에서는 rollup, cube, case, pivot에 대해서 함께 알아보도록 하겠습니다.



먼저 이전의 글에서 만들었던 sample데이터를 통해 실습을 진행해보도록 하겠습니다.


SELECT * FROM employee;




1. ROLLUP


먼저 알아볼 함수는 ROLLUP 입니다.

ROLLUP은 GROUP BY문과 함께 사용되는 함수인데, GROUP BY로 GROUPING된 행들 데이터 총합을 나타는데 사용합니다.

즉, employee테이블에서 부서별 그리고 직급 별 급여 합과 총합을 구하기 위해서 ROLLUP이 사용될 수 있습니다.


SELECT deptNo, job, SUM(salary) 급여총합

FROM employee

GROUP BY deptNo, job with ROLLUP;



사실상 부서별 그리고 직급별 급여의 합을 구하는 것은 SUM함수를 통해서 할 수 있었습니다.

하지만 위의 결과에서 빨간색으로 음영처리해놓은 결과는 이전의 SUM함수를 통해서 얻을 수 없었습니다.

첫번째 빨간색 음영 박스가 의미하는 것은 deptNO이 10인 부서에서 모든 직급(모든 job)의 급여총합을 의미합니다.

즉, deptNO이 10인 행들끼리 job을 모두 감았다(roll up)는 의미로 생각하시면 될 것 같습니다.

그리고 우리가 GROUP BY를 deptNo, job 로 GROUPING하였기 때문에, job으로 ROLLUP된 행 3개와 deptNO으로 ROLLUP 된 마지막 행(15번째 행)까지 총 4개의 추가 행이 결과로 나오게 됩니다.



2. CUBE


이번에는 CUBE에 대해서 알아봅니다.

쉽게 생각하면 CUBE는 ROLLUP 함수의 확장 형태라고 볼 수 있습니다.

우리가 위의 예에서 deptNo, job으로 ROLLUP을 진행하니, deptNo 끼리 job으로 묶인 salary의 총합(3개 행)과 deptNo와 job으로 묶인 salary의 총합(1개행)의 추가 데이터를 얻을 수 있었습니다.

만약 ROLLUP을 job, deptNo으로 진행했다면 어떨까요?

job끼리 deptNo으로 묶인 salary의 총합(6개 행 = job의 종류가 6개)과 job과 deptNo로 묶인 salary의 총합(1개행)의 추가 데이터를 얻을 수 있습니다.

CUBE는 이렇게 GROUPING 할 때 언급한 열의 순서에 따라 나타날 수 있는 ROLLUP의 경우의 수를 모두 나타내주게 됩니다. 그럼 바로 확인해보도록 하겠습니다.


SELECT deptNo, job, SUM(salary) 급여총합

FROM employee

GROUP BY deptNo, job with CUBE;



위의 결과를 보시면 먼저 3행은 과장 직급의 급여총합을 구한 것이며, 동일하게 5행, 9행, 13행, 15행, 17행은 각 직급별 급여총합을 나타내고 있습니다.

그리고 18행은 모든 deptNo와 job의 급여 총합을 나타내주고 있으며, 19행, 20행, 21행은 deptNo별 급여총합을 나타내고 있습니다.

위의 쿼리문을 아래와 같이 하면 행의 순서는 바뀔 수 있지만 결과는 동일합니다


SELECT deptNo, job, SUM(salary) 급여총합

FROM employee

GROUP BY job, deptNo with CUBE;



3. CASE


이번에 알아볼 CASE문은 C언어나 Java와 같은 프로그래밍 언어에서 사용되는 if ~ else ~ 문 또는 switch 문과 개념적으로 동일합니다.

기본적인 형식은 아래와 같습니다.


CASE when 조건식1 then 결과 1

          when 조건식1 then 결과2

          ...

          [ELSE 결과]

END [AS 칼럼 명]


여기서 대괄호로 표시된 것들은 생략할 수 있습니다.


CASE문은, 우리가 employee 테이블에서 부서별로 부서명을 직접 나타내고 싶을 때와 같은 경우에 사용할 수 있습니다. 부서번호가 10인 경우 전산부, 20인 경우 인사부, 30인 경우 경리부, 40인 경우 영업부로 나타내고 이 외에는 미정이라고 나타내보도록 합시다.


SELECT empName, deptNo,

CASE WHEN dpetNo = 10 THEN '전산부'

WHEN deptNo = 20 THEN '인사부'

WHEN deptNo = 30 THEN '경리부'

WHEN deptNo = 40 THEN '영업부'

ELSE '미정'

END AS 부서명

FROM employee;



위와 같이 우리가 조건을 설정한 대로 부서명이 올바르게 출력되었습니다.

조건식에는 범위에 대한 조건도 설정할 수 있습니다.


만약 부서번호가 20이하인 경우는 부서위치가 1층, 20초과인 경우에는 부서위치가 2층인 것으로 나타내고자 하면 다음과 같이 할 수 있습니다.


SELECT empName, deptNo,

CASE WHEN deptNo <= 20 THEN '1층'

WHEN deptNo > 20 THEN '2층'

END AS 부서위치

FROM employee;




4. PIVOT / UNPIVOT


마지막으로 알아볼 것은 PIVOT과 UNPIVOT입니다.

먼저 PIVOT에 대해서 알아보도록 하겠습니다.

PIVOT은 행으로 되어 있는 데이터를 열로 변환해서 표현하는 함수입니다.


우리가 가지고 있는 employee 테이블에서 열을 deptNo과 각 직급으로 나타내어 그 값을 표현하려면 어떻게 해야 할까요? 기존의 직급 데이터는 'job'이라는 속성에 행으로써 존재 했습니다. 하지만 사원, 부장 과 같이 행으로 되어있던 데이터를 열로 나타내려면 PIVOT을 사용하면 됩니다.

PIVOT문의 기본 형태는 다음과 같습니다.


SELECT [PIVOT열1], [PIVOT열2], ...

FROM 테이블명

PIVOT(나타내고자하는 값, FOR 행->열로 바꿀 열 IN ([PIVOT열1], [PIVOT열2], ...)) as 별칭


PIVOT문은 조금 어려울 수 있기 때문에 바로 실제 쿼리를 보면서 이해하시는 것을 추천드립니다.

위에서 이야기한 바를 쿼리로 나타내면 다음과 같습니다.


SELECT deptNo, [사원], [대리], [과장], [부장], [차장], [사장]

FROM employee

PIVOT(SUM(salary) FOR job In([사원], [대리], [과장], [부장], [차장], [사장])) AS job

ORDER BY deptNo;



위와 같이 행으로 되어있던 값을 열로 나타내어 테이블의 형태를 재구축 할 수 있습니다.

UNPIVOT과 같은 경우도 PIVOT과 활용법이 동일하지만 PIVOT이 행->열의 방식이었다면 UNPIVOT은 열->행의 방식인 것만 고려하면 됩니다.


블로그 이미지

Tigercow.Door

Web Programming / Back-end / Database / AI / Algorithm / DeepLearning / etc


안녕하세요. 문범우입니다.

이번 포스팅에서는 SUM, AVG, MIN, MAX와 같은 집계함수들에 대해서 알아보면서 GROUP BY절HAVING절에 대해서 다뤄보도록 하겠습니다.


1. 집계함수


집계함수는 값에 대해서 특정 연산을 수행하는 함수들을 이야기합니다.

합계를 구하는 SUM함수나 평균을 구하는 AVG함수, 개수를 세는 COUNT함수 등이 대표적입니다.

그럼 아래와 같이 이전 포스팅에서 사용했던 SampleDB를 사용하여 몇가지 집계함수에 대해서 함께 알아보도록 하겠습니다.




- SUM


SUM함수는 말 그대로 합계를 구하는 함수 입니다.

employee 테이블에서 연봉의 합계를 구하고자 할 때와 같은 경우에 아래와 같이 사용할 수 있습니다.


SELECT SUM(salary) FROM employee;




그럼 이번에는 employee 테이블에서 commission의 합계를 구해볼까요?

하지만 commission에는 NULL값이 포함되어 있습니다. 이전에는 NULL에 대한 연산을 진행할 때 그 결과가 NULL이 나오게 되어서 ISNULL이라는 함수를 이용했습니다.

그럼 집계함수에서는 어떨지 한번 확인해볼까요?


SELECT SUM(commission) FROM employee;



위의 결과에서 볼 수 있듯이 집계함수에서의 NULL은 무시가 됩니다.



- AVG


이어서 AVG함수에 대해서 알아봅시다.

AVG함수는 평균을 구하는 함수입니다. 그럼 월급의 평균은 어떠한지 확인해보도록 하겠습니다.


SELECT AVG(salary) FROM employee;



AVG함수 또한 NULL값이 존재할 때에는 NULL값은 무시하고 평균을 구하게 됩니다.



- MIN, MAX


MIN과 MAX는 최대값과 최소값을 구하는 함수 입니다.

다음과 같이 월급의 최소값과 최대값을 구해보도록 하겠습니다.


SELECT MIN(salary), MAX(salary) FROM employee;




- COUNT


마지막으로 알아볼 COUNT 함수는 개수를 세는 함수입니다.

이때 COUNT 또한 NULL값은 무시하게 됩니다. 즉, 값이 존재하는 데이터에 대한 개수만 세는 것이죠.

따라서 salary의 COUNT값과 commission의 COUNT값은 서로 다릅니다.


SELECT COUNT(salary), COUNT(commission) FROM employee;





2. GROUP BY


그런데 만약, 직급별 월급 평균, 월급 합계 등 특정 그룹별로 집계함수를 사용하고 싶을때는 어떻게 할까요?

테이블에서 특정 그룹을 만들 수 있도록 하는 것이 바로 GROUP BY 절 입니다.


즉, GROUP BY 'A' 라고 한다면 A칼럼에서 같은 것끼리 묶어서 하나의 GROUP를 만드는 것이죠.


그럼 바로 GROUP BY를 활용해보도록 하겠습니다.

위에서 이야기한 바와 같이 직급별 월급 평균은 다음과 같이 구할 수 있습니다.


SELECT job 직급, AVG(salary) 월급평균

FROM employee GROUP BY job;



위와 같이 직급별로 GROUP이 되어 AVG함수의 값이 나오는 것을 볼 수 있습니다.


하지만 우리가 다음과 같이 SELECT 문을 구성한다면 어떻게 될까요?


SELECT empName 이름, job 직급, AVG(salary) 월급평균

FROM employee GROUP BY job;


위의 구문을 실행시키면 아래와 같이 오류가 발생하게 됩니다.



오류메세지를 읽으며 한번 왜 오류가 발생하는지 생각해봅시다.

우리가 출력하고자 하는 empName 값이 집계함수에도 없고, GROUP BY 절에도 없어서 사용할 수 없다고 하네요.

그럼 empName이 집계함수나 GROUP BY 절에 있어야 한다는 의미인데, 왜 그럴까요?


우리가 결과를 출력하는 입장이라고 한번 생각해봅시다.

empName이 없을 때는 이전의 결과와 같이 직급과 월급평균을 잘 출력할 수 있었습니다.

예를 들어 과장의 월급평균은 483이란 결과를 가져왔죠.

그런데 이때 해당 레코드(행)에 empName을 출력해야 한다면, 어떠한 empName을 출력해야 할까요?

즉, 과장 직급의 483의 평균월급이라는 레코드는 '과장'이라는 값으로 여러개의 레코드가 그룹이 되어 있는 레코드 입니다. 즉 해당 레코드에는 여러개의 empName이 존재하는 것이죠.

따라서 SQL에서는 그 여러개 중에서 하나를 출력할 수 없기에 오류가 발생하는 것입니다.

만약 empName이 집계함수를 적용시키면 집계함수에 따른 값이 나오겠죠, 물론 문자열 값이기에 또 다른 오류가 발생하겠지만..

또한 empName을 GROUP BY절에 다시 써주면 아래와 같이 job과 empName이 동일한 레코드끼리 묶여서 나오기 때문에 사실상 현재 데이터에서는 모든 데이터를 출력하는 것과 같게 됩니다.


SELECT empName 이름, job 직급, AVG(salary) 월급평균

FROM employee GROUP BY job, empName;




3. HAVING


이번 포스팅에서 마지막으로 알아볼 것은 HAVING절 입니다.

HAVING은 간단하게 말해서, 우리가 위에서 배운 GROUP BY절을 통해 만들어진 GROUP에 대해서 조건을 거는 것 입니다.


그런데 우리는 이전에 조건을 거는 WHERE절에 대해서 학습하였습니다.


WHERE절과 HAVING절의 차이는 무엇일까요?


기본적으로 WHERE절은 모든 레코드(행)에 대해서 조건을 적용하게 됩니다.

하지만 HAVING절은 GROUP BY절을 통해 만들어진 GROUP 들에만 조건을 적용하는 것이죠.


이를 잘 이해하지 못하면 추후에 HAVING과 WHERE 사용에 있어 헷갈릴 수 있습니다.


그럼 바로 사용해보도록 하겠습니다.

각 직급에 대해 3명 이상인 직급과 그 인원수를 출력해보도록 하겠습니다.


SELECT job 직급, COUNT(job) '직급 수' FROM employee

GROUP BY job HAVING COUNT(job) >= 3;



위와 같이 사용됩니다.


그럼 만약,

"월급이 300만원 이상인 사람들에 대해서 직급별로 2명이상인 직급과 그 직급의 월급 평균을 구해라."

라면 어떻게 해야 할까요?

위와 같은 경우에 바로 WHERE절과 HAVING절이 같이 사용하게 됩니다.


SELECT job 직급, AVG(salary) 월급평균 FROM employee

WHERE salary >= 300

GROUP BY job HAVING COUNT(job) >= 2;



추후에 더 많은 데이터들을 대상으로 복잡한 쿼리문을 다루게 되면 충분히 헷갈릴 수 있는 점들이니 꼭 스스로 쿼리문을 작성해보면서 이해하기를 바랍니다.



이렇게 해서 집계함수와 GROUP BY, HAVING 절에 대해서 알아보았습니다.

궁금하거나 잘못된 점은 언제든 댓글이나 이메일, 카카오톡을 통해서 문의주시면 감사하겠습니다.


블로그 이미지

Tigercow.Door

Web Programming / Back-end / Database / AI / Algorithm / DeepLearning / etc