기록 블로그

프로그래머스 데브코스-데이터 엔지니어/TIL(Today I Learned)

05/11 24일차 데이터 웨어하우스와 SQL과 데이터분석 (4)

usiohc 2023. 5. 11. 17:00

데이터 웨어하우스와 SQL과 데이터분석


주요 메모 사항


JOIN이란?

  • sql 조인은 두 개 혹은 그 이상의 테이블들을 공통 필드를 가지고 머지하는데 사용된다.
  • Inner Join과 Left Join 으로 95%는 커버 가능함

 

JOIN시 고려해야할 점

  • 먼저 중복 레코드가 없고 Primary Key의 uniqueness가 보장됨을 체크
  • 조인하는 테이블간의 관계를 명확하게 정의
    • One to one 
      • 완전한 one to one : user_session_channel& session_timestamp
      • 한쪽이 부분집합이 되는 one to one: user_session_channel & session_transaction

 

    • One to many? (order vs order_items)
      • 이 경우 중복이 더 큰 문제됨 -> 증폭!!

 

    • Many to one? -> 방향만 바꾸면 One to many로 보는 것과 사실상 동일

 

    • Many to many?
      • 이런 경우는 많지 않으며 이는 one to one이나 one to many로 바꾸는 것이 가능하다면 변환하여 조인하는 것이 덜 위험

 

 


새로운 테이블 두 개 

  • VitalID가 join column

 

 

학부 Oracle 수업에서 Join과 procedure 한 학기를 굴렀더니 아직도 기억에 남아있다 -> 설명 생략

  • 위 표의 JOIN 이외에 CROSS JOIN, SELF JOIN 설명이 있었으나 생략 -> 사실상 쓸일이 없음

 

 

테이블 생성 

%%sql

DROP TABLE IF EXISTS raw_data.vital;
CREATE TABLE raw_data.vital (
    UserID int,
    VitalID	int,
    Date date,
    Weight int
);
INSERT INTO raw_data.vital VALUES
(100,	1, '2020-01-01', 75),
(100, 3, '2020-01-02', 78),
(101, 2, '2020-01-01', 90),
(101, 4, '2020-01-02', 95); 


%%sql

DROP TABLE IF EXISTS raw_data.alert;
CREATE TABLE raw_data.alert (
    AlertID int,
    VitalID	int,
    AlertType varchar(32),
    Date date,
    UserID int
);
INSERT INTO raw_data.alert VALUES
 (1,	4, 'WeightIncrease', '2020-01-01', 101),
 (2, NULL, 'MissingVital', '2020-01-04', 100),
 (3, NULL, 'MissingVital', '2020-01-04', 101);

 

 


INNER JOIN

  • 양쪽 테이블에서 매치가 되는 레코드들만 리턴함
  • 양쪽 테이블의 필드가 모두 채워진 상태로 리턴됨

 

%%sql

SELECT * FROM raw_data.Vital v
JOIN raw_data.Alert a ON v.vitalID = a.vitalID;

+----+----------+-----------+------------+----------+-----------+-----------+----------------+------------+----------+
|    |   userid |   vitalid | date       |   weight |   alertid |   vitalid | alerttype      | date       |   userid |
|----+----------+-----------+------------+----------+-----------+-----------+----------------+------------+----------|
|  0 |      101 |         4 | 2020-01-02 |       95 |         1 |         4 | WeightIncrease | 2020-01-01 |      101 |
+----+----------+-----------+------------+----------+-----------+-----------+----------------+------------+----------+

 

 

LEFT JOIN

  • 왼쪽 테이블의 레코드는 모두 리턴되며 오른쪽 테이블과 매칭이 되는 레코드들의 경우에는 오른쪽 테이블 레코드들의 컬럼들이 채워진 상태로 리턴됨.
  • 매칭이 안되는 왼쪽 테이블 레코드들은 오른쪽 테이블에서 들어오는 필드들은 NULL로 채워짐

 

%%sql

SELECT * FROM raw_data.Vital v
LEFT JOIN raw_data.Alert a ON v.vitalID = a.vitalID;

+----+----------+-----------+------------+----------+-----------+-----------+----------------+------------+----------+
|    |   userid |   vitalid | date       |   weight |   alertid |   vitalid | alerttype      | date       |   userid |
|----+----------+-----------+------------+----------+-----------+-----------+----------------+------------+----------|
|  0 |      100 |         1 | 2020-01-01 |       75 |       nan |       nan |                |            |      nan |
|  1 |      100 |         3 | 2020-01-02 |       78 |       nan |       nan |                |            |      nan |
|  2 |      101 |         2 | 2020-01-01 |       90 |       nan |       nan |                |            |      nan |
|  3 |      101 |         4 | 2020-01-02 |       95 |         1 |         4 | WeightIncrease | 2020-01-01 |      101 |
+----+----------+-----------+------------+----------+-----------+-----------+----------------+------------+----------+

 

 

 

FULL JOIN (OUTER JOIN)

  • 왼쪽 테이블과 오른쪽 테이블의 모든 레코드들을 리턴함
  • 매칭되는 경우에만 양쪽 테이블들의 모든 필드들이 채워진 상태로 리턴됨
%%sql

SELECT * FROM raw_data.Vital v
FULL JOIN raw_data.Alert a ON v.vitalID = a.vitalID;


+----+----------+-----------+------------+----------+-----------+-----------+----------------+------------+----------+
|    |   userid |   vitalid | date       |   weight |   alertid |   vitalid | alerttype      | date       |   userid |
|----+----------+-----------+------------+----------+-----------+-----------+----------------+------------+----------|
|  0 |      101 |         4 | 2020-01-02 |       95 |         1 |         4 | WeightIncrease | 2020-01-01 |      101 |
|  1 |      nan |       nan |            |      nan |         2 |       nan | MissingVital   | 2020-01-04 |      100 |
|  2 |      nan |       nan |            |      nan |         3 |       nan | MissingVital   | 2020-01-04 |      101 |
|  3 |      101 |         2 | 2020-01-01 |       90 |       nan |       nan |                |            |      nan |
|  4 |      100 |         1 | 2020-01-01 |       75 |       nan |       nan |                |            |      nan |
|  5 |      100 |         3 | 2020-01-02 |       78 |       nan |       nan |                |            |      nan |
+----+----------+-----------+------------+----------+-----------+-----------+----------------+------------+----------+

 

 

CROSS JOIN

  • 조인 조건 없이 두 개 테이블의 내용을 모두 조합한 결과 레코드들을 생성
%%sql

SELECT *
FROM (
    SELECT vitalid  -- 1,2,3,4
    FROM raw_data.vital
)
CROSS JOIN (
    SELECT alertid   -- 1,2,3
    FROM raw_data.alert
);


+----+-----------+-----------+
|    |   vitalid |   alertid |
|----+-----------+-----------|
|  0 |         1 |         1 |
|  1 |         1 |         2 |
|  2 |         1 |         3 |
|  3 |         3 |         1 |
|  4 |         3 |         2 |
|  5 |         3 |         3 |
|  6 |         2 |         1 |
|  7 |         2 |         2 |
|  8 |         2 |         3 |
|  9 |         4 |         1 |
| 10 |         4 |         2 |
| 11 |         4 |         3 |
+----+-----------+-----------+

#

%%sql

SELECT * FROM raw_data.Vital v
CROSS JOIN raw_data.Alert a;


+----+----------+-----------+------------+----------+-----------+-----------+----------------+------------+----------+
|    |   userid |   vitalid | date       |   weight |   alertid |   vitalid | alerttype      | date       |   userid |
|----+----------+-----------+------------+----------+-----------+-----------+----------------+------------+----------|
|  0 |      100 |         1 | 2020-01-01 |       75 |         1 |         4 | WeightIncrease | 2020-01-01 |      101 |
|  1 |      100 |         3 | 2020-01-02 |       78 |         1 |         4 | WeightIncrease | 2020-01-01 |      101 |
|  2 |      101 |         2 | 2020-01-01 |       90 |         1 |         4 | WeightIncrease | 2020-01-01 |      101 |
|  3 |      101 |         4 | 2020-01-02 |       95 |         1 |         4 | WeightIncrease | 2020-01-01 |      101 |
|  4 |      100 |         1 | 2020-01-01 |       75 |         2 |       nan | MissingVital   | 2020-01-04 |      100 |
|  5 |      100 |         3 | 2020-01-02 |       78 |         2 |       nan | MissingVital   | 2020-01-04 |      100 |
|  6 |      101 |         2 | 2020-01-01 |       90 |         2 |       nan | MissingVital   | 2020-01-04 |      100 |
|  7 |      101 |         4 | 2020-01-02 |       95 |         2 |       nan | MissingVital   | 2020-01-04 |      100 |
|  8 |      100 |         1 | 2020-01-01 |       75 |         3 |       nan | MissingVital   | 2020-01-04 |      101 |
|  9 |      100 |         3 | 2020-01-02 |       78 |         3 |       nan | MissingVital   | 2020-01-04 |      101 |
| 10 |      101 |         2 | 2020-01-01 |       90 |         3 |       nan | MissingVital   | 2020-01-04 |      101 |
| 11 |      101 |         4 | 2020-01-02 |       95 |         3 |       nan | MissingVital   | 2020-01-04 |      101 |
+----+----------+-----------+------------+----------+-----------+-----------+----------------+------------+----------+

 

SELF JOIN

%%sql

SELECT * FROM raw_data.Vital v1
JOIN raw_data.Vital v2 ON v1.vitalID = v2.vitalID;


+----+----------+-----------+------------+----------+----------+-----------+------------+----------+
|    |   userid |   vitalid | date       |   weight |   userid |   vitalid | date       |   weight |
|----+----------+-----------+------------+----------+----------+-----------+------------+----------|
|  0 |      100 |         1 | 2020-01-01 |       75 |      100 |         1 | 2020-01-01 |       75 |
|  1 |      100 |         3 | 2020-01-02 |       78 |      100 |         3 | 2020-01-02 |       78 |
|  2 |      101 |         2 | 2020-01-01 |       90 |      101 |         2 | 2020-01-01 |       90 |
|  3 |      101 |         4 | 2020-01-02 |       95 |      101 |         4 | 2020-01-02 |       95 |
+----+----------+-----------+------------+----------+----------+-----------+------------+----------+

 


BOOLEAN NULL 타입 처리

  • True or False 는 = 과 is 로 연산 가능
  • NULL 은 항상 is 와 is not 으로 연산

 

 

숙제 리뷰

 

OUT JOIN 이 필요한지 테이블 점검

%%sql

select distinct sessionid from raw_data.session_timestamp
minus
select distinct sessionid from raw_data.user_session_channel;

+-------------+
| sessionid   |
+-------------+

%%sql

select * from raw_data.session_transaction
where amount <= 0

+----+----------------------------------+------------+----------+
|    | sessionid                        | refunded   |   amount |
|----+----------------------------------+------------+----------|
|  0 | 3d194d58a6470121c92f29c1ee4c936f | False      |        0 |
|  1 | 50aaa83c9c2d1d1f3ebc6c732c1abc8c | False      |        0 |
|  2 | 7fbfc161a3b873bf2119c788ed93d1f4 | False      |        0 |
|  3 | d288a67e5fe3b80c0ccb9531e87d437a | False      |        0 |
|  4 | dfc95d616451863a4fe614534e08261c | False      |        0 |
|  5 | 297b51d372955449d68d0b67ffda8c80 | False      |        0 |
|  6 | 52660fd5af844425740f3a7bf5151008 | False      |        0 |
|  7 | 99e17fbe90095024e6c982c85d43d150 | False      |        0 |
|  8 | d572948a93127fa250a9aa8a122a4403 | False      |        0 |
|  9 | e00747f11c12e85717de726cc6c2f188 | False      |        0 |
+----+----------------------------------+------------+----------+

 

먼저 유일한 사용자 수부터 세보기

SELECT LEFT(ts, 7) "month",
 usc.channel,
 COUNT(DISTINCT userid) uniqueUsers
 FROM raw_data.user_session_channel usc
 JOIN raw_data.session_timestamp t ON t.sessionid = usc.sessionid
 GROUP BY 1, 2
 ORDER BY 1, 2;
 
 +----+---------+-----------+---------------+
|    | month   | channel   |   uniqueusers |
|----+---------+-----------+---------------|
|  0 | 2019-05 | Facebook  |           247 |
|  1 | 2019-05 | Google    |           253 |
|  2 | 2019-05 | Instagram |           234 |
|  3 | 2019-05 | Naver     |           237 |
|  4 | 2019-05 | Organic   |           238 |
|  5 | 2019-05 | Youtube   |           244 |
|  6 | 2019-06 | Facebook  |           414 |
|  7 | 2019-06 | Google    |           412 |
|  8 | 2019-06 | Instagram |           410 |
|  9 | 2019-06 | Naver     |           398 |
| 10 | 2019-06 | Organic   |           416 |
| 11 | 2019-06 | Youtube   |           400 |
| 12 | 2019-07 | Facebook  |           558 |
| 13 | 2019-07 | Google    |           556 |
| 14 | 2019-07 | Instagram |           567 |
| 15 | 2019-07 | Naver     |           553 |
| 16 | 2019-07 | Organic   |           557 |
| 17 | 2019-07 | Youtube   |           564 |
| 18 | 2019-08 | Facebook  |           611 |
| 19 | 2019-08 | Google    |           610 |
| 20 | 2019-08 | Instagram |           621 |
| 21 | 2019-08 | Naver     |           626 |
| 22 | 2019-08 | Organic   |           608 |
| 23 | 2019-08 | Youtube   |           614 |
| 24 | 2019-09 | Facebook  |           597 |
| 25 | 2019-09 | Google    |           599 |
| 26 | 2019-09 | Instagram |           588 |
| 27 | 2019-09 | Naver     |           592 |
| 28 | 2019-09 | Organic   |           592 |
| 29 | 2019-09 | Youtube   |           588 |
| 30 | 2019-10 | Facebook  |           698 |
| 31 | 2019-10 | Google    |           699 |
| 32 | 2019-10 | Instagram |           707 |
| 33 | 2019-10 | Naver     |           713 |
| 34 | 2019-10 | Organic   |           709 |
| 35 | 2019-10 | Youtube   |           705 |
| 36 | 2019-11 | Facebook  |           688 |
| 37 | 2019-11 | Google    |           688 |
| 38 | 2019-11 | Instagram |           669 |
| 39 | 2019-11 | Naver     |           667 |
| 40 | 2019-11 | Organic   |           677 |
| 41 | 2019-11 | Youtube   |           677 |
+----+---------+-----------+---------------+

 

 

Summary Table 만들기

%%sql

--혹시 기존에 생성되어 있으면 삭제
DROP TABLE IF EXISTS adhoc.minsu_monthly_channel_summary;

--Summary Table 생성
CREATE TABLE adhoc.minsu_monthly_channel_summary
AS
SELECT TO_CHAR(ts, 'YYYY-MM') year_month, 
    usc.channel, 
    COUNT(DISTINCT usc.userid) unique_users, 
    COUNT(DISTINCT CASE WHEN amount>0 THEN userid END) paid_users,
    ROUND(paid_users*100.0 / NULLIF(unique_users,0) ,2) conversion_rate, 
    SUM(amount) gross_revenue, 
    SUM(CASE WHEN refunded is False THEN amount
        ELSE 0 END) net_revenue
  FROM raw_data.user_session_channel usc
  JOIN raw_data.session_timestamp st ON usc.sessionid = st.sessionid
  LEFT JOIN raw_data.session_transaction str ON usc.sessionid = str.sessionid
GROUP BY 1, 2;

--정상적으로 생성되었는지 확인
SELECT * FROM adhoc.minsu_monthly_channel_summary;



+----+--------------+-----------+----------------+--------------+-------------------+-----------------+---------------+
|    | year_month   | channel   |   unique_users |   paid_users |   conversion_rate |   gross_revenue |   net_revenue |
|----+--------------+-----------+----------------+--------------+-------------------+-----------------+---------------|
|  0 | 2019-09      | Facebook  |            597 |           27 |                 4 |            2270 |          2270 |
|  1 | 2019-07      | Organic   |            557 |           22 |                 3 |            1600 |          1600 |
|  2 | 2019-08      | Google    |            610 |           27 |                 4 |            2210 |          1894 |
|  3 | 2019-07      | Youtube   |            564 |           36 |                 6 |            2210 |          2037 |
|  4 | 2019-05      | Facebook  |            247 |           14 |                 5 |            1199 |           997 |
|  5 | 2019-05      | Organic   |            238 |           17 |                 7 |            1846 |          1571 |
|  6 | 2019-09      | Youtube   |            588 |           15 |                 2 |            1301 |          1301 |
|  7 | 2019-08      | Instagram |            621 |           28 |                 4 |            2129 |          2001 |
|  8 | 2019-05      | Youtube   |            244 |            9 |                 3 |             529 |           529 |
|  9 | 2019-06      | Facebook  |            414 |           22 |                 5 |            1578 |          1578 |
| 10 | 2019-11      | Instagram |            669 |           25 |                 3 |            2116 |          2116 |
| 11 | 2019-10      | Organic   |            709 |           31 |                 4 |            2762 |          2608 |
| 12 | 2019-09      | Organic   |            592 |           22 |                 3 |            1267 |          1267 |
| 13 | 2019-09      | Google    |            599 |           25 |                 4 |            1872 |          1691 |
| 14 | 2019-06      | Instagram |            410 |           21 |                 5 |            1462 |          1418 |
| 15 | 2019-06      | Youtube   |            400 |           17 |                 4 |            1042 |          1042 |
| 16 | 2019-08      | Naver     |            626 |           22 |                 3 |            1829 |          1551 |
| 17 | 2019-05      | Naver     |            237 |           11 |                 4 |             867 |           844 |
| 18 | 2019-11      | Youtube   |            677 |           45 |                 6 |            3532 |          3331 |
| 19 | 2019-08      | Youtube   |            614 |           18 |                 2 |             987 |           950 |
| 20 | 2019-06      | Organic   |            416 |           14 |                 3 |            1129 |           940 |
| 21 | 2019-11      | Facebook  |            688 |           25 |                 3 |            1678 |          1678 |
| 22 | 2019-11      | Naver     |            667 |           26 |                 3 |            2234 |          1987 |
| 23 | 2019-08      | Facebook  |            611 |           18 |                 2 |            1009 |          1009 |
| 24 | 2019-11      | Google    |            688 |           26 |                 3 |            2286 |          2235 |
| 25 | 2019-07      | Facebook  |            558 |           32 |                 5 |            2222 |          2144 |
| 26 | 2019-10      | Youtube   |            705 |           34 |                 4 |            2492 |          2319 |
| 27 | 2019-05      | Google    |            253 |           10 |                 3 |             580 |           580 |
| 28 | 2019-05      | Instagram |            234 |           11 |                 4 |             959 |           770 |
| 29 | 2019-11      | Organic   |            677 |           34 |                 5 |            2626 |          2255 |
| 30 | 2019-10      | Facebook  |            698 |           29 |                 4 |            1650 |          1641 |
| 31 | 2019-07      | Naver     |            553 |           19 |                 3 |            1547 |          1547 |
| 32 | 2019-10      | Instagram |            707 |           33 |                 4 |            2568 |          2395 |
| 33 | 2019-10      | Naver     |            713 |           32 |                 4 |            2695 |          2695 |
| 34 | 2019-08      | Organic   |            608 |           26 |                 4 |            1643 |          1606 |
| 35 | 2019-09      | Instagram |            588 |           20 |                 3 |            1260 |          1122 |
| 36 | 2019-06      | Google    |            412 |           13 |                 3 |             947 |           947 |
| 37 | 2019-07      | Instagram |            567 |           24 |                 4 |            1896 |          1766 |
| 38 | 2019-07      | Google    |            556 |           21 |                 3 |            1558 |          1385 |
| 39 | 2019-09      | Naver     |            592 |           21 |                 3 |            1996 |          1996 |
| 40 | 2019-10      | Google    |            699 |           30 |                 4 |            2150 |          2098 |
| 41 | 2019-06      | Naver     |            398 |           15 |                 3 |            1090 |          1090 |
+----+--------------+-----------+----------------+--------------+-------------------+-----------------+---------------+

 

 

원하는 TABLE 생성

%%sql

DROP TABLE IF EXISTS adhoc.minsu_monthly_channel_summary;
CREATE TABLE adhoc.minsu_monthly_channel_summary AS
    SELECT LEFT(ts, 7) "month",
        channel,
        COUNT(DISTINCT usc.userid) uniqueUsers,
        COUNT(DISTINCT CASE WHEN amount > 0 THEN usc.userid END) paidUsers,
        ROUND(paidUsers::float*100/NULLIF(uniqueUsers, 0),2) conversionRate,
        SUM(amount) grossRevenue,
        SUM(CASE WHEN refunded is False THEN amount END) netRevenue
    FROM raw_data.user_session_channel usc
        LEFT JOIN raw_data.session_timestamp t ON t.sessionid = usc.sessionid
        LEFT JOIN raw_data.session_transaction st ON st.sessionid = usc.sessionid
    GROUP BY 1, 2;

 select * from adhoc.minsu_monthly_channel_summary;
 
 +----+---------+-----------+---------------+-------------+------------------+----------------+--------------+
|    | month   | channel   |   uniqueusers |   paidusers |   conversionrate |   grossrevenue |   netrevenue |
|----+---------+-----------+---------------+-------------+------------------+----------------+--------------|
|  0 | 2019-10 | Organic   |           709 |          31 |             4.37 |           2762 |         2608 |
|  1 | 2019-08 | Youtube   |           614 |          18 |             2.93 |            987 |          950 |
|  2 | 2019-08 | Organic   |           608 |          26 |             4.28 |           1643 |         1606 |
|  3 | 2019-08 | Naver     |           626 |          22 |             3.51 |           1829 |         1551 |
|  4 | 2019-06 | Instagram |           410 |          21 |             5.12 |           1462 |         1418 |
|  5 | 2019-09 | Naver     |           592 |          21 |             3.55 |           1996 |         1996 |
|  6 | 2019-09 | Google    |           599 |          25 |             4.17 |           1872 |         1691 |
|  7 | 2019-10 | Facebook  |           698 |          29 |             4.15 |           1650 |         1641 |
|  8 | 2019-11 | Instagram |           669 |          25 |             3.74 |           2116 |         2116 |
|  9 | 2019-07 | Instagram |           567 |          24 |             4.23 |           1896 |         1766 |
| 10 | 2019-07 | Google    |           556 |          21 |             3.78 |           1558 |         1385 |
| 11 | 2019-06 | Naver     |           398 |          15 |             3.77 |           1090 |         1090 |
| 12 | 2019-06 | Organic   |           416 |          14 |             3.37 |           1129 |          940 |
| 13 | 2019-05 | Google    |           253 |          10 |             3.95 |            580 |          580 |
| 14 | 2019-09 | Facebook  |           597 |          27 |             4.52 |           2270 |         2270 |
| 15 | 2019-09 | Youtube   |           588 |          15 |             2.55 |           1301 |         1301 |
| 16 | 2019-11 | Google    |           688 |          26 |             3.78 |           2286 |         2235 |
| 17 | 2019-07 | Youtube   |           564 |          36 |             6.38 |           2210 |         2037 |
| 18 | 2019-05 | Youtube   |           244 |           9 |             3.69 |            529 |          529 |
| 19 | 2019-07 | Facebook  |           558 |          32 |             5.73 |           2222 |         2144 |
| 20 | 2019-08 | Instagram |           621 |          28 |             4.51 |           2129 |         2001 |
| 21 | 2019-07 | Naver     |           553 |          19 |             3.44 |           1547 |         1547 |
| 22 | 2019-05 | Naver     |           237 |          11 |             4.64 |            867 |          844 |
| 23 | 2019-09 | Instagram |           588 |          20 |             3.4  |           1260 |         1122 |
| 24 | 2019-10 | Naver     |           713 |          32 |             4.49 |           2695 |         2695 |
| 25 | 2019-06 | Google    |           412 |          13 |             3.16 |            947 |          947 |
| 26 | 2019-10 | Instagram |           707 |          33 |             4.67 |           2568 |         2395 |
| 27 | 2019-10 | Google    |           699 |          30 |             4.29 |           2150 |         2098 |
| 28 | 2019-06 | Youtube   |           400 |          17 |             4.25 |           1042 |         1042 |
| 29 | 2019-11 | Youtube   |           677 |          45 |             6.65 |           3532 |         3331 |
| 30 | 2019-06 | Facebook  |           414 |          22 |             5.31 |           1578 |         1578 |
| 31 | 2019-11 | Organic   |           677 |          34 |             5.02 |           2626 |         2255 |
| 32 | 2019-09 | Organic   |           592 |          22 |             3.72 |           1267 |         1267 |
| 33 | 2019-07 | Organic   |           557 |          22 |             3.95 |           1600 |         1600 |
| 34 | 2019-05 | Facebook  |           247 |          14 |             5.67 |           1199 |          997 |
| 35 | 2019-11 | Facebook  |           688 |          25 |             3.63 |           1678 |         1678 |
| 36 | 2019-11 | Naver     |           667 |          26 |             3.9  |           2234 |         1987 |
| 37 | 2019-08 | Google    |           610 |          27 |             4.43 |           2210 |         1894 |
| 38 | 2019-05 | Organic   |           238 |          17 |             7.14 |           1846 |         1571 |
| 39 | 2019-08 | Facebook  |           611 |          18 |             2.95 |           1009 |         1009 |
| 40 | 2019-05 | Instagram |           234 |          11 |             4.7  |            959 |          770 |
| 41 | 2019-10 | Youtube   |           705 |          34 |             4.82 |           2492 |         2319 |
+----+---------+-----------+---------------+-------------+------------------+----------------+--------------+

 

 

 


 

COALESCE

  • NULL 값을 다른 값으로 바꿔주는 함수
  • 다만 COALESCE(exp1, exp2, exp3, ...)
    • exp1부터 인자를 하나씩 살펴서 NULL이 아닌 값이 나오면 그걸 리턴함
    • 끝까지 갔는데도 모두 NULL이면 최종적으로 NULL을 리턴
%%sql

SELECT
     value,
     COALESCE(value, 0) -- value가 NULL이면 0을 리턴
FROM raw_data.count_test;


+----+---------+------------+
|    |   value |   coalesce |
|----+---------+------------|
|  0 |     nan |          0 |
|  1 |       1 |          1 |
|  2 |       1 |          1 |
|  3 |       0 |          0 |
|  4 |       0 |          0 |
|  5 |       4 |          4 |
|  6 |       3 |          3 |
+----+---------+------------+

 

공백 혹은 예약키워드를 필드 이름으로 사용하려면?

  • "" 으로 선언하면 된다.
CREATE TABLE keeyong.test (
 group int primary key,
 'mailing address' varchar(32)
);

 


공부하며 어려웠던 내용