SQL(7)(data types, date format, data wrangling, using string functions to clean data)

DATA TYPES









string - 최대 필드 길이가 1024자인 모든 문자

date/time - 년, 월, 일, 시, 분, 초 값을 YYYY-MM-DD hh : mm : ss로 저장

number - 최대 17개의 유효 자릿수 십진 정밀도를 가진 숫자

boolean - TRUE 또는 FALSE 값

열의 데이터 유형 변경

데이터 유형을 쿼리에서 언제든지 변경할 수 있다.

연습문제

테이블의 funding_total_usd 및 founded_at_clean열을 각각 다른 형식 지정 함수를 사용하여 문자열로 변환

1
2
3
SELECT CAST(funding_total_usd AS varchar) AS funding_total_usd_string,
       founded_at_clean::varchar AS founded_at_string
  FROM tutorial.crunchbase_companies_clean_date
cs









DATE FORMAT

1
2
3
4
SELECT permalink,
       founded_at
  FROM tutorial.crunchbase_companies_clean_date
 ORDER BY founded_at
cs










1
2
3
4
5
SELECT permalink,
       founded_at,
       founded_at_clean
  FROM tutorial.crunchbase_companies_clean_date
 ORDER BY founded_at_clean
cs

다음은 동일한 테이블의 예지만 정리된 날짜가 있는 필드가 있다. 정리된 날짜 필드는 실제로 문자열로 저장되지만 시간순으로 정렬된다.








1
2
3
4
5
6
7
8
9
SELECT companies.permalink,
       companies.founded_at_clean,
       acquisitions.acquired_at_cleaned,
       acquisitions.acquired_at_cleaned -
         companies.founded_at_clean::timestamp AS time_to_acquisition
  FROM tutorial.crunchbase_companies_clean_date companies
  JOIN tutorial.crunchbase_acquisitions_clean_date acquisitions
    ON acquisitions.company_permalink = companies.permalink
 WHERE founded_at_clean IS NOT NULL
cs








1
2
3
4
5
6
SELECT companies.permalink,
       companies.founded_at_clean,
       companies.founded_at_clean::timestamp +
         INTERVAL '1 week' AS plus_one_week
  FROM tutorial.crunchbase_companies_clean_date companies
 WHERE founded_at_clean IS NOT NULL
cs

위의 예에서 time_to_acquisition열이 다른 날짜가 아니라 간격임을 알 수 있다.

interval함수를 사용하여 간격을 도입할 수 있다.









1
2
3
4
5
SELECT companies.permalink,
       companies.founded_at_clean,
       NOW() - companies.founded_at_clean::timestamp AS founded_time_ago
  FROM tutorial.crunchbase_companies_clean_date companies
 WHERE founded_at_clean IS NOT NULL
cs

간격은 '10초' 또는 '5개월'과 같은 일반 용어를 사용하여 정의된다. 또한 date열과 열을 더하거나 빼면 위의 쿼리에서와 같이 다른 열이 생성된다.

now()함수를 사용하여 현재시간을 코드에 추가할 수 있다.









연습문제

설립 3, 5, 10년 이내에 인수한 회사 수를 세는 쿼리를 작성, 범주별로 그룹화하고 설립 날짜가 있는 행으로만 제한

1
2
3
4
5
6
7
8
9
10
11
12
13
14
SELECT companies.category_code,
       COUNT(CASE WHEN acquisitions.acquired_at_cleaned <= companies.founded_at_clean::timestamp + INTERVAL '3 years'
                       THEN 1 ELSE NULL END) AS acquired_3_yrs,
       COUNT(CASE WHEN acquisitions.acquired_at_cleaned <= companies.founded_at_clean::timestamp + INTERVAL '5 years'
                       THEN 1 ELSE NULL END) AS acquired_5_yrs,
       COUNT(CASE WHEN acquisitions.acquired_at_cleaned <= companies.founded_at_clean::timestamp + INTERVAL '10 years'
                       THEN 1 ELSE NULL END) AS acquired_10_yrs,
       COUNT(companies.category_code) AS total
  FROM tutorial.crunchbase_companies_clean_date companies
  JOIN tutorial.crunchbase_acquisitions_clean_date acquisitions
    ON acquisitions.company_permalink = companies.permalink
 WHERE founded_at_clean IS NOT NULL
 GROUP BY companies.category_code
 ORDER BY total DESC
cs








DATA WRANGLING

데이터 병합 또는 반자동 도구를 사용하여 데이터를 보다 편리하게 사용할 수 있도록 한 원래 데이터를 다른 형식으로 수동으로 변환하거나 매핑하는 프로세스다.

즉, 데이터를 보다 쉽게 작업 할 수 있는 형식으로 프로그래밍 방식으로 변환하는 프로세스다.

USING STRING FUNCTIONS TO CLEAN DATA

LEFT, RIGHT, LENGTH, TRIM

left는 문자열 왼쪽에서 특정 수의 문자를 가져와 별도의 문자열로 표시할 수 있다.

구문은 left(string, number of characters)이다.

right는 left랑 동일하지만 오른쪽에서 표시한다.

1
2
3
4
5
SELECT incidnt_num,
       date,
       LEFT(date, 10) AS cleaned_date,
       RIGHT(date, 17) AS cleaned_time
  FROM tutorial.sf_crime_incidents_2014_01
cs








length는 글자 수를 반환한다.

1
2
3
4
5
SELECT incidnt_num,
       date,
       LEFT(date, 10) AS cleaned_date,
       RIGHT(date, LENGTH(date) - 11) AS cleaned_time
  FROM tutorial.sf_crime_incidents_2014_01
cs








trim함수는 문자열의 시작과 끝에서 문자를 제거하는데 사용된다.

1
2
3
SELECT location,
       TRIM(both '()' FROM location)
  FROM tutorial.sf_crime_incidents_2014_01
cs

''에 포함된 모든 문자는 문자열의 시작, 끝 또는 양쪽에서 제거된다.








POSITION, STRPOS

position은 하위 문자열을 지정한 다음 해당 하위 문자열이 대상 문자열에 처음나타나는 문자번호와 동일한 숫자값을 반환한다. 대소문자 구분.

1
2
3
4
SELECT incidnt_num,
       descript,
       POSITION('A' IN descript) AS a_position
  FROM tutorial.sf_crime_incidents_2014_01
cs








strpos함수를 사용하여 동일한 결과를 얻을 수 있다. in을 ,로 바꾸고 문자열과 하위문자열의 순서를 전화하면 된다.

1
2
3
4
SELECT incidnt_num,
       descript,
       STRPOS(descript, 'A') AS a_position
  FROM tutorial.sf_crime_incidents_2014_01
cs








SUBSTR

문자열 중간에서 시작할 수 있다. substr(string, starting character position, of characters)

1
2
3
4
SELECT incidnt_num,
       date,
       SUBSTR(date, 42) AS day
  FROM tutorial.sf_crime_incidents_2014_01
cs










연습문제

'location'필드를 위도와 경도에 대한 별도의 필드로 구분하는 쿼리

1
2
3
4
SELECT location,
       TRIM(leading '(' FROM LEFT(location, POSITION(',' IN location) - 1)) AS lattitude,
       TRIM(trailing ')' FROM RIGHT(location, LENGTH(location) - POSITION(',' IN location) ) ) AS longitude
  FROM tutorial.sf_crime_incidents_2014_01
cs









CONCAT

여러 열의 문자열을 함께 결합할 수 있다.

1
2
3
4
5
SELECT incidnt_num,
       day_of_week,
       LEFT(date, 10) AS cleaned_date,
       CONCAT(day_of_week, ', ', LEFT(date, 10)) AS day_and_date
  FROM tutorial.sf_crime_incidents_2014_01
cs










연습문제

lat및 lon필드를 연결하여 location필드와 동일한 필드를 형성(답은 소수 정밀도가 다름)

1
2
3
SELECT CONCAT('(', lat, ', ', lon, ')') AS concat_location,
       location
  FROM tutorial.sf_crime_incidents_2014_01
cs








또는 아래와 같이 (||)를 사용하여 동일한 연결을 수행할 수 있다.

1
2
3
4
5
SELECT incidnt_num,
       day_of_week,
       LEFT(date, 10) AS cleaned_date,
       day_of_week || ', ' || LEFT(date, 10) AS day_and_date
  FROM tutorial.sf_crime_incidents_2014_01
cs








연습문제

concat대신 ||를 사용하여 위의 연습문제와 같이 location필드 만들기

1
2
3
SELECT '(' || lat || ', ' || lon || ')' AS concat_location,
       location
  FROM tutorial.sf_crime_incidents_2014_01
cs








YYYY-MM-DD형식의 날짜 열을 만드는 쿼리

1
2
3
4
SELECT incidnt_num,
       date,
       SUBSTR(date, 74|| '-' || LEFT(date, 2|| '-' || SUBSTR(date, 42) AS cleaned_date
  FROM tutorial.sf_crime_incidents_2014_01
cs










UPPER, LOWER

upper : 모든 문자열을 대문자로 표시

lower : 모든 문자열을 소문자로 표시

1
2
3
4
5
SELECT incidnt_num,
       address,
       UPPER(address) AS address_upper,
       LOWER(address) AS address_lower
  FROM tutorial.sf_crime_incidents_2014_01
cs








연습문제

'category'필드를 반환하지만 첫번째 문자는 대문자로 나머지는 소문자로 표시하는 쿼리

1
2
3
4
SELECT incidnt_num,
       category,
       UPPER(LEFT(category, 1)) || LOWER(RIGHT(category, LENGTH(category) - 1)) AS category_cleaned
  FROM tutorial.sf_crime_incidents_2014_01
cs











문자열을 날짜로 바꾸기

1
2
3
4
5
SELECT incidnt_num,
       date,
       (SUBSTR(date, 74|| '-' || LEFT(date, 2||
        '-' || SUBSTR(date, 42))::date AS cleaned_date
  FROM tutorial.sf_crime_incidents_2014_01
cs









연습문제

date, time열을 사용하여 정확한 타임 스탬프를 만드는 쿼리 작성. 정확히 1주일 후의 필드도 포함

1
2
3
4
5
6
7
SELECT incidnt_num,
       (SUBSTR(date, 74|| '-' || LEFT(date, 2||
        '-' || SUBSTR(date, 42|| ' ' || time || ':00')::timestamp AS timestamp,
       (SUBSTR(date, 74|| '-' || LEFT(date, 2||
        '-' || SUBSTR(date, 42|| ' ' || time || ':00')::timestamp
        + INTERVAL '1 week' AS timestamp_plus_interval
  FROM tutorial.sf_crime_incidents_2014_01
cs










날짜필드를 분해하려면 extract를 사용하여 조각을 하나씩 분리할 수 있다.

1
2
3
4
5
6
7
8
9
10
SELECT cleaned_date,
       EXTRACT('year'   FROM cleaned_date) AS year,
       EXTRACT('month'  FROM cleaned_date) AS month,
       EXTRACT('day'    FROM cleaned_date) AS day,
       EXTRACT('hour'   FROM cleaned_date) AS hour,
       EXTRACT('minute' FROM cleaned_date) AS minute,
       EXTRACT('second' FROM cleaned_date) AS second,
       EXTRACT('decade' FROM cleaned_date) AS decade,
       EXTRACT('dow'    FROM cleaned_date) AS day_of_week
  FROM tutorial.sf_crime_incidents_cleandate
cs








date_trunc함수를 사용하여 가장 가까운 측정 단위로 날짜를 반올림 할 수 있다. 

1
2
3
4
5
6
7
8
9
10
SELECT cleaned_date,
       DATE_TRUNC('year'   , cleaned_date) AS year,
       DATE_TRUNC('month'  , cleaned_date) AS month,
       DATE_TRUNC('week'   , cleaned_date) AS week,
       DATE_TRUNC('day'    , cleaned_date) AS day,
       DATE_TRUNC('hour'   , cleaned_date) AS hour,
       DATE_TRUNC('minute' , cleaned_date) AS minute,
       DATE_TRUNC('second' , cleaned_date) AS second,
       DATE_TRUNC('decade' , cleaned_date) AS decade
  FROM tutorial.sf_crime_incidents_cleandate
cs








연습문제

주별로 보고된 사고 수를 계산하는 쿼리 작성.

1
2
3
4
5
SELECT DATE_TRUNC('week', cleaned_date)::date AS week_beginning,
       COUNT(*) AS incidents
  FROM tutorial.sf_crime_incidents_cleandate
 GROUP BY week_beginning
 ORDER BY week_beginning
cs












오늘 날짜 또는 시간을 포함하려면 다음과 같이 from절 없이 실행할 수 있다.

1
2
3
4
5
6
SELECT CURRENT_DATE AS date,
       CURRENT_TIME AS time,
       CURRENT_TIMESTAMP AS timestamp,
       LOCALTIME AS localtime,
       LOCALTIMESTAMP AS localtimestamp,
       NOW() AS now
cs





at time zone를 사용하여 시간을 다른 시간대로 표시할 수 있다.

1
2
SELECT CURRENT_TIME AS time,
       CURRENT_TIME AT TIME ZONE 'PST' AS time_pst
cs





연습문제

신고된지 얼마나 오래되었는지를 보여주는 쿼리를 작성. 태평양 표준시(UTC-8)로 가정.

1
2
3
4
5
SELECT incidnt_num,
       cleaned_date,
       NOW() AT TIME ZONE 'PST' AS now,
       NOW() AT TIME ZONE 'PST' - cleaned_date AS time_ago 
  FROM tutorial.sf_crime_incidents_cleandate
cs








COALESCE

null값을 대체하는데 사용할 수 있다.

1
2
3
4
5
SELECT incidnt_num,
       descript,
       COALESCE(descript, 'No Description')
  FROM tutorial.sf_crime_incidents_cleandate
 ORDER BY descript DESC
cs









댓글

이 블로그의 인기 게시물

SQL(9)(performance tuning queries, pivoting data)

데이터 크롤링(3주차)

SQL(8)(writing subqueries, window functions)