문제 설명

지나다니는 길을 'O', 장애물을 'X'로 나타낸 직사각형 격자 모양의 공원에서 로봇 강아지가 산책을 하려합니다. 산책은 로봇 강아지에 미리 입력된 명령에 따라 진행하며, 명령은 다음과 같은 형식으로 주어집니다.

  • ["방향 거리", "방향 거리" … ]

예를 들어 "E 5"는 로봇 강아지가 현재 위치에서 동쪽으로 5칸 이동했다는 의미입니다. 로봇 강아지는 명령을 수행하기 전에 다음 두 가지를 먼저 확인합니다.

  • 주어진 방향으로 이동할 때 공원을 벗어나는지 확인합니다.
  • 주어진 방향으로 이동 중 장애물을 만나는지 확인합니다.

위 두 가지중 어느 하나라도 해당된다면, 로봇 강아지는 해당 명령을 무시하고 다음 명령을 수행합니다.
공원의 가로 길이가 W, 세로 길이가 H라고 할 때, 공원의 좌측 상단의 좌표는 (0, 0), 우측 하단의 좌표는 (H - 1, W - 1) 입니다.

 

 

공원을 나타내는 문자열 배열 park, 로봇 강아지가 수행할 명령이 담긴 문자열 배열 routes가 매개변수로 주어질 때, 로봇 강아지가 모든 명령을 수행 후 놓인 위치를 [세로 방향 좌표, 가로 방향 좌표] 순으로 배열에 담아 return 하도록 solution 함수를 완성해주세요.

 

제한사항

  • 3 ≤ park의 길이 ≤ 50
    • 3 ≤ park[i]의 길이 ≤ 50
      • park[i]는 다음 문자들로 이루어져 있으며 시작지점은 하나만 주어집니다.
        • S : 시작 지점
        • O : 이동 가능한 통로
        • X : 장애물
    • park는 직사각형 모양입니다.
  • 1 ≤ routes의 길이 ≤ 50
    • routes의 각 원소는 로봇 강아지가 수행할 명령어를 나타냅니다.
    • 로봇 강아지는 routes의 첫 번째 원소부터 순서대로 명령을 수행합니다.
    • routes의 원소는 "op n"과 같은 구조로 이루어져 있으며, op는 이동할 방향, n은 이동할 칸의 수를 의미합니다.
      • op는 다음 네 가지중 하나로 이루어져 있습니다.
        • N : 북쪽으로 주어진 칸만큼 이동합니다.
        • S : 남쪽으로 주어진 칸만큼 이동합니다.
        • W : 서쪽으로 주어진 칸만큼 이동합니다.
        • E : 동쪽으로 주어진 칸만큼 이동합니다.
      • 1 ≤ n ≤ 9

 

입출력 예

park routes result
['SOO', 'OOO', 'OOO'] ['E 2', 'S 2', 'W 2'] [2,1]
['SOO', 'OXX', 'OOO'] ['E 2', 'S 2', 'W 2'] [0,1]
['OSO', 'OOO', 'OXO', 'OOO'] ['E 2', 'S 3', 'W 2'] [0,0]

 

 

입출력 예 설명

입출력 예 #1

입력된 명령대로 동쪽으로 2칸, 남쪽으로 2칸, 서쪽으로 1칸 이동하면 [0,0] -> [0,2] -> [2,2] -> [2,1]이 됩니다.

입출력 예 #2

입력된 명령대로라면 동쪽으로 2칸, 남쪽으로 2칸, 서쪽으로 1칸 이동해야하지만 남쪽으로 2칸 이동할 때 장애물이 있는 칸을 지나기 때문에 해당 명령을 제외한 명령들만 따릅니다. 결과적으로는 [0,0] -> [0,2] -> [0,1]이 됩니다.

입출력 예 #3

처음 입력된 명령은 공원을 나가게 되고 두 번째로 입력된 명령 또한 장애물을 지나가게 되므로 두 입력은 제외한 세 번째 명령만 따르므로 결과는 다음과 같습니다. [0,1] -> [0,0]

 

요점 정리

  • 맵과 루트 존재
  • 맵에는 시작정보, 장애물 정보
  • 루트는 방향과 거리 정보 제공
def solution(park, routes):
    dictionary = {'E':1, 'W':-1, 'N':-1, 'S':1,}    # 동서남북의 방향 딕셔너리 생성

    park_map = []   # 맵리스트 생성
    first_point = [0,0] # 처음 지점 생성

    for idxy, part in enumerate(park):  # park 리스트를 순환하며, 지점 특성을 파악 및 시작 지점 좌표 확인
        temp = []
        for idxx, i in enumerate(part):
            if i == 'S':
                first_point = [idxy, idxx]
            temp.append(i)
        park_map.append(temp)

    X_max = len(park_map[0])    # 맵 가로, 세로 최대 길이를 저장, 차후 맵길이를 넘어서는 route를 제거하기 위함
    y_max = len(park_map)

    for route in routes:    # 루트에 대한 처리 시작
        direction = route.split( )[0]   # split 함수를 사용해 루트의 방향과 이동 거리를 저장
        distance = int(route.split( )[1])
        if direction in ('E', 'W'): # 같은 횡방향 이동인 E, W에 대해 처리
            
            if X_max > dictionary[direction]*distance + first_point[1] >=0: # 현재 x좌표 + 이동거리가 최대 값보다 작은 조건에서 route 수행
                new_x = first_point[1] + dictionary[direction]*distance
                
                if direction == 'E':    # 이동 경로에 해당하는 맵 경로에 X가 없는 경우에 first_point 최신화
                    obstacle_list = park_map[first_point[0]][first_point[1]:new_x+1]
                    if 'X' not in obstacle_list:
                        first_point[1] = new_x
                if direction == 'W':    # 이동 경로에 해당하는 맵 경로에 X가 없는 경우에 first_point 최신화
                    obstacle_list = park_map[first_point[0]][new_x:first_point[1]]
                    if 'X' not in obstacle_list:
                        first_point[1] = new_x

        elif direction in ('N', 'S'):   # 같은 종방향 이동인 E, W에 대해 처리
            if y_max > dictionary[direction]*distance + first_point[0] >=0: # 현재 ㅛ좌표 + 이동거리가 최대 값보다 작은 조건에서 route 수행
                new_y = first_point[0] + dictionary[direction]*distance
                
                if direction == 'S':    # 이동 경로에 해당하는 맵 경로에 X가 없는 경우에 first_point 최신화
                    obstacle_list = [row[first_point[1]] for row in park_map[first_point[0]:new_y+1]]
                    if 'X' not in obstacle_list:
                        first_point[0] = new_y
                if direction == 'N':    # 이동 경로에 해당하는 맵 경로에 X가 없는 경우에 first_point 최신화
                    obstacle_list = [row[first_point[1]] for row in park_map[new_y:first_point[0]]]
                    if 'X' not in obstacle_list:
                        first_point[0] = new_y
    return first_point

관계형 데이터베이스

  • RDB(Relational Database)라고 불리는 관계형 데이터베이는 말 그대로 관계형 데이터 모델에 기초를 둔 데이터베이스이다.
  • 관계형 데이터베이스의 설계는 모든 데이터를 2차원 테이블 형태로 표현한 뒤 각 테이블 간의 관계를 정의하는 것으로 시작된다.
  • RDBMS(Relational Database Management System)는 이러한 RDB를 관리 감독하기 위한 시스템이다.
  • Ex. Oracle, SQL Server(MSSQL), MySQL, MariaDB, PostgreSQL 등

Table

  • 관계형 데이터베이스를 표현할때 사용하는 형식이다.(엑셀 표 형식과 유사)
  • 항목을 나타내는 각각의 세로 열을 칼럼(Column)이라고 한다.
  • 각각의 가로 행을 로우(Row)라고 한다.
  • 테이블은 관계형 데이터베이스의 기본 단위이고 일반적으로 데이터베이스는 여러 개의 테이블로 구성된다.
  • 데이터를 저장하는 주된 목적은 데이터를 활용하는 데에 있고 우리는 그것을 테이블 형태로 조회하고 변경하고 삭제할 수 있다.
게임 유저명 플레이타임(시간)
메이플 닉네임메 10
닉네임롤 20

 

SQL(Structured Query Language)

  • SQL은 관계형 데이터베이스에서 데이터를 다루기 위해 사용하는 언어이다.
  • 간단한 SQL 작성 방법은 뻔하기에 누가 작성하든 비슷하지만 라인 수가 많아지는 복잡한 SQL은 어떻게 작성하냐에 따라 성능 차가 확연하기에 SQL을 잘 작성하고 튜닝하는 것이 중요하다.

SELECT

  • 저장되어 있는 데이터를 조회하고자 할 때 사용하는 명령어이다.
SELECT 컬럼1, 컬럼2, ... FROM 테이블 WHERE 컬럼1 = '아무개';
  • 컬럼을 따로 명시하지 않고 *(asterisk)를 쓰면 전체 컬럼이 조회되며 조회되는 컬럼의 순서는 테이블 컬럼 순서와 동일하다.
SELECT * FROM 테이블;
  • 별도의 WHERE 절이 없으면 테이블 전체 Row가 조회된다.
SELECT BAND.BAND_NAME, BAND_MEMBER.MEMBER_NAME
FROM BAND, BAND_MEMBER
WHERE BAND.BAND_CODE = BAND_MEMBER.BAND_CODE;

SELECT B.BAND_NAME, BM.MEMBER_NAME
FROM BAND B, BAND_MEMBER BM
WHERE B.BAND_CODE = BM.BAND_CODE;
  • 테이블이나 컬럼 명에 별도의 별칭을(Alias)을 붙여줄 수 있는데, 붙여주는 목적은 줄여쓰기 위함이다.
  • FROM절에서 정의한다.
  • 테이블명에 Alias를 설정했을 경우 테이블명 대신 Alisa를 사용해야 한다. 아닐 경우 문법 에러가 발생한다.

산술 연산자

  • 수학에서 사용하는 사칙연산의 기능을 가진 연산자이다.
  •  NULL이 포함된 연산을 주의하자
    • 다른 컬럼끼리 연산(가로 연산)에서 NULL이 포함되어 있으면 결과 값은 NULL이다
    • 다른 로우끼리 연산(세로 연산)에서 NULL이 포함되어 있으면 결과 값은 NULL을 제외하고 연산한 결과이다.
연산자 의미 우선순위
() 우선순위 조정 1
* 곱하기 2
/ 나누기
+ 더하기 3
- 빼기

합성 연산자

  • 문자와 문자를 연결할 때 사용하는 연산자이다.
SELECT 'S'||'Q'||'L'||'개'||'발'||'자' AS SQLD FROM DUAL

SQLD
SQL개발자

 

함수

  • 데이터베이스에서 매핑을 제공하는 함수들이 있다.
  • 문자 함수
    • CHR(ASCII 코드)
      • ASCII 코드는 총 128개의 문자를 숫자로 표현할 수 있도록 정의해 놓은 코드이다.
      • ASCII 코드를 인수로 입력하였을때 매핑되는 문자가 무엇인지를 알려주는 함수이다.
      • Ex. CHR(65) → A
    • LOWER(문자열)
      • 문자열을 소문자로 변환해주는 함수이다.
      • Ex. LOWER('KIM') → kim
    • UPPER(문자열)
      • 문자열을 대문자로 변환해주는 함수이다.
    • LTRIM(문자열 [,특정 문자]) *[]는 옵션
      • 특정 문자를 따로 명시해주지 않으면 문자열의 왼쪽 공백을 제거한다.
      • 특정 문자를 명시한 경우 문자열을 왼쪽부터 한 글자씩 특정 문자와 비교하여 특정 문자에 포함되어 있으면 제거하고 포함되지 않았으면 멈춘다.
      • 문자 사이의 공백은 제거하지 않는다.
      • SQL Server(MSSQL)의 경우 공백 제거만 가능하다.
      • Ex. LTRIM('    KIM') → KIM
      • Ex. LTRIM('DATABASE', 'DE') → ATABASE
    • RTLIM(문자열 [,특정 문자]) *[]는 옵션
      • LTRIM과 방향만 반대이고 같은 기능을 가진다.
    • TRIM([위치] [특정 문자] [FROM] 문자열) *[]는 옵션
      • 옵션이 없는 경우 문자열 양쪽의 공백을 제거한다.
      • 옵션이 있는 경우 옵션에 따라 지정된 위치에서 한 글자씩 특정 문자와 비교하여 제거하고 다르면 멈춘다.
      • SQL Server(MSSQL)의 경우 공백 제거만 가능하다.
      • Ex. TRIM('   KIM   ') → KIM
      • Ex. TRIM(LEADING 'K' FROM 'KIM') → IM
      • Ex. TRIM(TRALLING 'M' FROM 'KIM') → KI
    • SUBSTR(문자열, 시작점 [,길이]) *[]는 옵션
      • 문자열의 원하는 부분만 잘라서 반환해주는 함수이다.
      • 길이를 명시하지 않은 경우 문자열의 시작부터 끝까지 반환된다.
      • 길이 옵션보다 문자열이 짧은 경우 문자열의 끝까지 반환된다.
      • Ex. SUBSTR('교촌치킨허니콤보', 3, 2) → 치킨
      • Ex. SUBSTR('교촌치킨허니콤보', 5, 4) → 허니콤보
    • LENGTH(문자열)
      • 문자열의 길이를 반환해주는 함수이다.
      •  Ex. LENGTH('교촌치킨허니콤보') → 8
    • REPLACE(문자열, 변경 전 문자열 [변경 후 문자열]) *[]는 옵션
      • 문자열에서 변경 전 문자열을 찾아 변경 후 문자열로 바꿔주는 함수이다. 변경 후 문자열을 명시해 주지 않으면 문자열에서 변경 전 문자열을 제거한다.
      • Ex. REPLACE('교촌치킨허니콤보', '허니', '꿀') → 교촌치킨꿀콤보
      • Ex. SELECT REPLACE('교촌치킨허니콤보', '허니') → 교촌치킨콤보
  • 숫자 함수
    • ABS(수)
      • 수의 절대값을 반환해주는 함수이다.
        • ABS(-10) → 10 
      • SIGN(수)
        • 수의 부호를 반환해주는 함수이다. 양수이면 1, 음수이면 -1, 0이면 0을 반환한다
        • Ex. SIGN(-7) → 1
      • ROUND(수, [,자릿수]) *[]는 옵션
        • 수를 지정된 소수점 자릿수까지 반올림하여 반환해주는 함수이다.
        • 자릿수를 명시하지 않으면 기본값은 0이며 반올림된 정수로 반환한다.
        • 자릿수가 음수인 경우 지정된 정수브를 반올림하여 반환한다.
        • Ex. ROUND(178.356, 1) → 178.4
        • Ex. ROUND(178.356, -2) → 200
      • TRUNC(수 [,자릿수])
        • 수를 지정된 소수점 자릿수까지 버림하여 반환해주는 함수이다.
        • 자릿수를 명시하지 않았을 경우 기본 값을 0이며 버림된 정수를 반환한다.
        • 자릿수가 음수인 경우 지정된 정수부에서 버림하여 반환한다.
        • Ex. TRUNC(55.62, 1) → 55.6
        • Ex. TRUNC(55.62, -1) → 50
      • CELL(수)
        • 소수점 이하의 수를 올림한 정수를 반환해주는 함수이다.
        • SQL Server(MSSQL)의 경우 CELING(문자열)
        • Ex. CELL(72.86) → 73
        • Ex. CELL(-33.4) → 33
      • FLOOR(수)
        • 소수점 이하의 수를 버림한 정수를 반환해주는 함수이다.
        • 음수에서는 '버림'이 아닌 '내림'임에 주의하자
        • Ex. FLOOR(22.3) → 22
        • Ex. FLOOR(-22.3) → -23
      • MOD(수1, 수2)
        • 수1을 수2로 나눈 나머지를 반환해주는 함수이다.
        • MOD 함수의 두 번째 인자값이 0이면 첫 번째 인자 값이 결과로 도출된다.
        • MOD 함수의 두 인자값이 모두 음수이면 나머지도 그대로 음수값으로 도출된다.
        • Ex. MOD(15, 7) → 1
        • Ex. MOD(15, -4) → 3
    • 날짜 함수
      • SYSDATE
        • 현재의 연, 월, 일, 시, 분, 초를 반환해주는 함수이다.
        • nls_data_format에 따라서 sysdate의 출력 양식은 달라질 수 있다.
        • SQL Server(MSSQL)의 경우 GETDATE()
        • Ex. SYSDATE → 2022-08-31 20:12:56
      • EXTRACT(특정 단위 FROM 날짜 데이터)
        • 날짜 데이터에서 특정 단위(YEAR, MONTH, DAY HOUR, MINUTE, SECOND)만을 출력해서 반환해주는 함수이다,
        • Ex. EXTRACT(YEAR FROM SYSDATE) → 2022
        • Ex. EXTRACT(MONTH FROM SYSDATE) → 8
        • Ex. EXTRACT(DAY FROM SYSDATE) → 31
      • ADD_MONTH(날짜 데이터, 특정 개월 수)
        • 날짜 데이터에서 특정 개월 수를 더한 날짜를 반환해주는 함수이다.
        • 날짜의 이전 달이나 다음 달에 기준 날짜의 일자가 존재하지 않으면 해당 월의 마지막 일자가 반환된다.
        • SQL Server(MSSQL)의 경우 DATEADD(MONTH, 특정 개월 수, 날짜 데이터)
        • Ex. ADD_MONTH(TO_DATE('2022-08-31', 'YYYY-MM-DD'), -1) → 2022-09-30
    • 반환 함수
      • 명시적 형변환과 함시적 형변환
      • 데이터베이스에서 데이터 유형에 대한 형변환을 할 수 있는 방법은 두 가지가 있다.
        • 명시적 형변환: 변환 함수를 사용하여 데이터 유형 변환을 명시적으로 나타냄
        • 암시적 형변환: 데이터베이스가 내부적으로 알아서 데이터 유형을 변환함
      • Ex. VARCHAR 유형의 BIRTHDAY 컬럼을 숫자와 비교할 경우, 데이터 베이스는 오류를 뱉지 않고 내부적으로 BIRTHDAY 컬럼을 NUMBER형으로 변환하게 되는데 이럴 때 쓰이는 것이 암시적 형변환이다.
      • 암시적 형변환이 가능하다고해서 데이터 유형을 고려하기 않고 SQL 작성을 하는 것은 성능 저하를 유발한다. 
      • 따라서 되도록 명시적 형변환을 사용하는 것이 좋다.
      • 명시적 형변환에 쓰이는 함수
        • SQL Server(MSSQL)의 경우 CONVERT나 CAST 함수를 사용할 수 있다.
        • TO_NUMBER(문자열)
          •  문자열을 숫자형으로 변환해주는 함수이다.
          • Ex. TO_NUMBER('1234') → 1234
          • Ex. TO_NUMBER('abc') → Error 발생!
        • TO_CHAR(수 or 날짜 [, 포맷]) * []는 옵션
          • 수나 날짜형의 데이터를 포맷 형식의 문자형으로 변환해주는 함수이다.
          • Ex. TO_CHAR(1234) → '1234'
          • Ex. TO_CHAR(SYSDATE, 'YYYYMMDD HH24MISS') → 20220831 203309
        • TO_DATE(문자열, 포맷)
          • 포맷 형식의 문자형의 데이터를 날짜형으로 변환해주는 함수이다.
          • Ex. TO_DATE('20220831', 'YYYYMMDD') → '2022-08-31'
포맷 표현 의미 포맷표현 의미
YYYY HH 시(12)
MM HH24 시(24)
DD MI
    SS
  • NULL 관련 함수
    • NVL(인수1, 인수2)
      • 인수 1의 값이 NULL일 경우 인수2를 반환하고 NULL이 아닐 경우 인수1을 반환해주는 함수이다.
      • SQL Server(MMSQL)의 경우 ISNULL(인수1, 인수2)
      • Ex. NVL(REVIEW_SCORE, 0)
        • REVIEW_SCORE가 NULL인 경우 0를 반환
        • NULL이 아닌 경우 REVIEW_SCORE를 반환
    • NULLIF(인수1, 인수2)
      • 인수1과 인수2가 같으면 NULL을 반환한다.
      • 인수1과 인수2가 같지 않으면 인수1을 반환한다.
      • Ex. NULLIF(5, 5) → NULL
      • Ex. NULLIF(5, 3) → 5
    • COALESCE(인수1, 인수2, 인수3...)
      • NULL이 아닌 최초의 인수를 반환해주는 함수이다.
      • Ex. COALESCE(NULL, NULL, '000-000-000', '000@SQLD.COM', 5, NULL) → '000-000-000'
  • CASE
    • CASE는 함수와 성격이 같기는 하지만 표현방식이 함수라기보다는 구문에 가깝다고 할 수 있다.
    • 문장으로는 '~이면 ~이고', '~이면 ~이다' 식으로 표현되는 구문이다.
    • 필요에 따라 각 CASE를 여러 개로 늘릴 수도 있다.
    • 같은 기능을 하는 함수로는 Oracle의 DECODE 함수가 있다.
    • *[]는 옵션
    • 다음 구문은 같은 결과를 반환한다.
CASE WHEN SUBWAY_LINE='1' THEN 'BLUE'
	WHEN SUBWAY_LINE='2' THEN 'GREEN'
	WHEN SUBWAY_LINE='3' THEN 'ORANGE'
	[ELSE 'GRAY']
END

CASE SUBWAY_LINE
	WHEN '1' THEN 'BLUE'
    WHEN '2' THEN 'GREEN'
    WHEN '3' THEN 'ORANGE'
    [ELSE 'GRAY']
END

DECODE (SUBWAY_LINE,'1','BLUE','2','GREEN','3','ORANGE'[,GRAY])

 

WHERE 절

  • INSERT를 제외한 DML문을 수행할 때 원하는 데이터만 골라 수행할 수 있도록 해주는 구문이다.
  • 예를들면 NAME 컬럼이 '이지은'인 컬럼만 SELECT 할 수도 있고 '이지은'이 아닌 컬럼만 SELECT 할 수도 있다.
  • UPDATE나 DELETE도 마찬가지이다.
  • WHERE 절의 위치는 다음과 같다.
  • Ex. SELECT 컬럼1, 컬럼2 ... FROM 테이블 WHERE 조건절;
  • Ex. UPDATE 테이블명 SET 컬럼명 = 새로운 데이터 WHERE 조건절;
  • Ex. DELETE FROM 테이블 WHERE 조건절;
  • 다양한 WHERE 절에 대하여 알아보자.

 

비교 연산자

비교 연산자 의미 예시
= 같음 where col = 10
작음 where col < 10
<= 작거나 같음 where col <= 10
> where col > 10
>= 크거나 같음 where col >= 10
# 다음 쿼리는 CITY가 Paris인 행을 조회한다.
SELECT FIRST_NAME, LAST_NAME, CITY
	FROM MEMBER
    WHERE CITY = 'Paris';
    
# 다음 쿼리는 MEMBER_NO가 10보다 작은 행을 조회한다.
SELECT MEMBER_NO, FIRST_NAEM, LAST_NAME
	FROM MEMBER
    WHERE MEMBER_NO < 10;
    
# 다음 쿼리는 FIRST_NAME과 Mark의 데이터 타입이 맞지 않아 에러가 발생한다.
SELECT FIRST_NAME, LAST_NAME, EMAIL
	FROM MEMBER
    WHER FIRST_NAME = Mark;
    
# FIRST_NAME과 같은 문자형 컬럼을 비교 조건으로 사용하려면 우측 상수값을 반드시 인용부호로 감싸야한다.

 

부정 비교 연산자

부정 비교 연산자 의미 예시
!= 같지 않음 where col1 != 10
^= 같지 않음 where col1 ^= 10
<> 같지 않음 where col1 <> 10
not 컬럼명 = 같지 않음 where not col1 = 10
not 컬럼명 > 크지 않음 where not col1 > 10
# 다음 쿼리는 FAVORITES이 Y가 아닌 행을 조회한다.
SELECT PLAY_ID, NAME, FAVORITES
	FROM PLAY_LIST
    WHERE FAVORITES <> 'Y';

 

SQL 연산자

SQL 연산자  의미 예시
BETWEEN A AND B A와 B 사이(A, B 포함) where col between 1 and 10
LIKE '비교 문자열' 비교 문자열을 포함 where col like '방탄%'
where col like '%소년단'
where col like '%탄소년%'
where col like '방_소%'
IN (LIST) LIST 중 하나와 일치 where col in (1, 3, 5)
IS NULL NULL 값 where col is null
# 다음 쿼리는 PLAY_ID가 1 이상, 5이하인 행을 조회한다.
SELECT PLAY_ID, NAME, FAVORITES
	FROM PLAY_LIST
WHERE PLAY_ID BETWEEN 1 AND 5;

# 위의 쿼리는 다음과 같이 표현할 수도 있다.
SELECT PLAY_ID, NAME, FAVORITES
	FROM PLAY_LIST
WHERE PLAY_ID >= 1 AND PLAY_ID <=5;

# 다음 쿼리는 NAME이 Classical로 시작되는 행을 조회한다.
SELECT PLAY_ID, NAME, FAVORITES
	FROM PLAY_LIST
WHERE NAME LIKE 'Classical%';

# 다음 쿼리는 NAME이 Music으로 끝나는 행을 조회한다.
SELECT PLAY_ID, NAME, FAVORITES
	FROM PLAY_LIST
WHERE NAME LIKE '%Music';

# 다음 쿼리는 NAME이 M으로 시작하고 S로 끝나는 행을 조회한다.
SELECT PLAY_ID, NAME, FAVORITES
	FROM PLAY_LIST
WHERE NAME LIKE 'M&S';

# 다음 쿼리는 NAMEDP 101이 포함된 행을 조회한다.
SELECT PLAY_ID, NAME, FAVORITES
	FROM PLAY_LIST
WHERE NAME LIKE '&101%';

# 다음 쿼리는 TITLE이 IT Staff이거나 IT Manager인 행을 조회한다.
SELECT LAST_NAME, FIRST_NAEM, TITLE
	FROM EMPLOYEE
WHERE TITLE IN ('IT Staff', 'IT Manager');

# 위의 쿼리는 다음과 같이 표현할 수도 있다.
SELECT LAST_NAME, FIRST_NAME, TITLE
	FROM EMPLOYEE
WHERE (TITLE = 'IT Staff' OR TITLE = 'IT Manager');

# 다음 쿼리는 COMPANY가 NULL인 행을 조회한다.
SELECT FIRST_NAME, LAST_NAME, COMPANY
	FROM MEMBER
WHERE COMPANY IS NULL;

 

부정 SQL 연산자

부정 SQL 연산자 의미 예시
NOT BETWEEN A AND B A와 B의 사이가 아님(A, B 미포함) where col not between 1 and 10
NOT IN (LIST) LIST 중 일치하는 것이 없음 where col not in (1, 3, 5)
IS NOT NULL NULL 값이 아님 where col is not null
# 다음 쿼리는 PLAY_ID가 1이상, 5이하가 아닌 행을 조회한다.
SELECT PLAY_ID, NAME, FAVORITES
	FROM PLAY_LIST
WHERE PLAY_ID NOT BETWEEN 1 AND 5;

# 위의 쿼리는 다음과 같이 표현할 수도 있다.
SELECT PLAY_ID, NAME, FAVORITES
	FROM PLAY_LIST
WHERE NOT (PLAY_ID BTWEEN 1 AND 5);

SELECT PLAY_ID, NAME, FAVORITES
	FROM PLAY_LIST
WHERE NOT (PLAY_ID >= 1 AND PLAY_ID <= 5);

SELECT PLAY_ID, NAME, FAVORITES
	FROM PLAY_LIST
WHERE PLAY_ID < 1 OR PLAY_ID > 5;

# 다음 쿼리는 TITLE이 IT Staff와 IT Manager가 아닌 행을 조회한다.
SELECT LAST_NAME, FIRST_NAME, TITLE
	FROM EMPLOYEE
WHERE TITLE NOT IN ('IT Staff', 'IT Manager');

# 위의 쿼리는 다음과 같이 표현할 수도 있다.
SELECT LAST_NAME, FIRST_NAME, TITLE
	FROM EMPLOYEE
WHERE NOT (TITLE IN ('IT Staff', 'IT Manager'));

SELECT LAST_NAME, FIRST_NAME, TITLE
	FROM EMPLOYEE
WHERE NOT (TITLE = 'IT Staff' OR TITLE = 'IT Manager');

SELECT LAST_NAME, FIRST_NAME, TITLE
	FROM EMPLOYEE
WHERE TITLE <> 'IT Staff' AND TITLE <> 'IT Manager';

# 다음 쿼리는 COMPANY가 NULL이 아닌 행을 조회한다.
SELECT FIRST_NAME, LAST_NAME, COMPANY
	FROM MEMBER
WHERE COMPANY IS NOT NULL;

 

논리 연산자

  • 논리 연산자에는 처리 순서가 존재하는데 SQL에 명시된 순서와는 관계없다.
  • () → NOT → AND → OR 순으로 처리된다.
논리 연산자 의미 예시
NOT TRUE이면 FALSE이고 FALSE이면 TRUE where not col > 10
AND 모든 조건이 TRUE여야 함 where col>1 and col<10
OR 하나 이상의 조건이 TRUE여야 함 where col=1 or col=10

 

GROUP BY, HAVING 절

  • GROUP BY
    • GROUP BY는 말 그대로 데이터를 그룹별로 묶을 수 있도록 해주는 절이다.
    • GROUP 뒤에 수단의 전치사인 BY가 붙었기 때문에 GROUP BY 뒤에는 그룹핑의 기준이 되는 컬럼이 온다.
    • 컬럼은 하나또는 그 이상이 될 수 있다.
  • 집계 함수
    • 데이터를 그룹별로 나누면 그룹별로 집계 데이터를 도출하는 것이 가능해진다.
COUNT(*) 전체 Row를 Count하여 반환
COUNT(컬럼) 컬럼값이 Null인 Row를 제외하고 Count하여 반환
COUNT(DISTINCT 컬럼) 컬럼값이 Null이 아닌 Row에서 중복을 제거한 Count를 반환
SUM(컬럼) 컬럼값들의 합계 반환
AVG(컬럼) 컬럼값들의 평균 반환
MIN(컬럼) 컬럼값들의 최솟값 반환
MAX(컬럼) 컬럼값들의 최댓값 반환
  • HAVING
    • HAVING 절은 GROUP BY 절을 사용할 때 WHERE 절처럼 사용하는 조건절이라고 생각하면된다.
    • 주로 데이터를 그룹핑한 후 특정 그룹을 골라낼 때 사용한다.
    • HAVING 절은 논리적으로 GROUP BY 절 이후에 수행되기에 그룹핑 후에 가능한 집계 함수로 조건을 부여할 수 있다.
    • HAVING 절은 논리적으로 SELECT 절 전에 수행되기에 SELECT 절에 명시되지 않은 집계 함수로도 조건을 부여하는 것이 가능하다.
    • 주의할 점은 WHERE 절을 사용해도 되는 조건까지 HAVING 절로 써버리면 성능상 불리할 수 있다는 점이다.
    • WHERE 절에서 필터링을 선행해야 GROUP BY 할 데이터량이 줄어들어 성능에 유리하다.
SELECT 문의 논리적 수행 순서

SELECT        → 5
FROM           → 1 
WHERE        → 2
GROUP BY   → 3
HAVING        → 4
ORDER BY   → 6

 

ORDER BY 절

  • ORDER BY
    • ORDER BY 절은 SELECT 문에서 논리적으로 맨 마지막에 수행된다.
    • ORDER BY 절을 사용하여 SELECT한 데이터를 정렬할 수 있다.
    • ORDER BY 절을 따로 명시하지 않으면 데이터는 임의의 순서대로 출력된다.
    • ORDER BY 절 뒤에는 정렬의 기준이 되는 컬럼이 오게된다.
    • 기준이 되는 컬럼은 하나 또는 그 이상이 될 수도 있다.
    • ORDER BY 절 뒤에 오는 컬럼에는 옵션이 붙을 수 있으며 종류는 다음과 같다.
      • ASC(Ascending) : 오름차순
      • DESC(Descending) : 내림차순
      • 옵션 생략 시 ASC가 기본값이 된다.
    • 정렬의 기준이 되는 컬럼에 NULL 데이터가 포함되어 있는 경우 데이터베이스 종류에 따라 정렬의 위치가 달라진다.
    • Oracle의 경우에는 NULL을 최댓값으로 취급하기 때문에 오름차순을 했을 경우 맨 마지막에 위치한다.(SQL Server는 반대)
    • 만약 순서를 변경하고 싶다면 ORDER BY 절에 NULLS FIRST, NULLS LAST 옵션을 써서 NULL의 정렬상 순서를 변경할 수 있다.

 

JOIN

  • JOIN이란?
    • 테이터베이스에서 조인이란 각기 다른 테이블을 한 번에 보여줄 때 쓰는 쿼리이다.
    • 실무에서 SQL을 작성할 때 8할이 JOIN 쿼리라고 얘기해도 무방하다.
    • JOIN되는 두 테이블에 모두 존재하는 컬럼의 경우 컬럼명 앞에 반드시 테이블명이나 ALIAS를 명시해주어야 함
  • EQUI JOIN
    • EQUI JOIN은 Equal(=) 조건으로 JOIN하는 것으로 가장 흔히 볼 수 있는 JOIN의 방식이라고 할 수 있다
SELECT A.PRODUCT_CODE,
	A.PRODUCT_NAME,
    B.MEMBER_ID,
    B.CONTENT,
    B.REG_DATE
FROM PRODUCT A,
	PRODUCT_REVIEW B
WHERE A.PRODUCT_CODE = B.PRODUCT_CODE
	AND A.PRODUCT_CODE = '100001';
  • Non EQUI JOIN
    • Non EQUI JOIN은 Equal(=) 조건이 아닌 다른 조건(BETWEEN, >, >=, <, <=)으로 JOIN 하는 방식이다.
    • 예를 들어 이벤트 기간 동안 리뷰를 작성한 고객에게 사은품을 주는 행사를 하고 있다고 가정해보자.
    • 이 경우 리뷰 테이블과 이벤트 테이블이 JOIN되어야 할 것이다.
SELECT A.EVENT_NAME,
	B.MEMBER_NAME,
    B.CONTENT,
    B.REG_DATE
FROM EVENT A,
	PRODUCT_REVIEW B
WHERE B.REG_DATE BETWEEN A.START_DATE AND A.END_DATE;
  • OUTER JOIN
    • OUTER JOIN은 앞서 본 JOIN과는 다르게 JOIN 조건에 만족하지 않는 행들도 출력되는 형태이다.
    • LEFT OUTER JOIN의 경우 LEFT TABLE과 RIGHR TABLE의 데이터 중 JOIN에 성곤한 데이터와 그렇지 못한 나머지 LEFT TABLE의 데이터가 함께 출력된다.
    • Oracle에서는 모든 행이 출력되는 테이블의 반대편 테이블의 옆에(+) 기로를 붙여 작성해주면 된다.
# LEFT OUTER JOIN이다.
SELECT A.PRODUCT_CODE,
	A.PRODUCT_NAME,
    B.MEMBER_ID,
    B.CONTENT,
    B.REG_DATE
FROM PRODUCT A,
	PRODUCT_REVIEW B
WHERE A.PRODUCT_CODE = B.PRODUCT_CODE(+);

 

STANDARD JOIN

  • DBMS가 여러개가 존재하는데 호환성 이슈가 발생하여 하나의 표준을 정한것이다.
  • ANSI SQL, 표준 조인이라는 말을 많이 사용한다.
  • INNER JOIN
    • JOIN 조건에 충족하는 데이터만 출력되는 방식이다.
    • 앞서 본 SQL과의 차이점은 JOIN 조건을 ON 절을 사용하여 작성해야 한다는 점이다.
SELECT A.PRODUCT_CODE,
	A.PRODUCT_NAME,
    B.MEMBER_ID,
    B.CONTENT,
    B.REG_DATE
FROM PRODUCT A INNER JOIN PRODUCT REVIEW B
	ON A.PRODUCT_CODE = B.PRODUCT_CODE;
  • OUTER JOIN
    • JOIN 조건에 충족하는 데이터가 아니어도 출력될 수 있는 방식이다.
    • LEFT OUTER JOIN
      • SQL에서  왼쪽에 표기된 테이블의 데이터는 무조건 출력되는 JOIN이다.
      • 오른쪽 테이블에 JOIN되는 데이터가 없는 ROW들은 오른쪽 테이블 컬럼의 값이 NULL로 출력된다.
    • RIGHT OUTER JOIN
      • SQL에서 오른쪽에 표기된테이블의 데이터는 무조건 출력되는 방식이다.
      • 왼족 테이블에 JOIN되는 데이터가 없는 ROW들은 왼쪽 테이블 컬럼의 값이 NULL로 출력된다.
    • FULL OUTER JOIN
      • 왼쪽, 오룬쪽 테이블의 데이터가 모두 출력되는 방식이다.
      • LEFT OUTER JOIN과 RIGHT OUTER JOIN의 합집합이라고 이해하면 쉽다.(단 중복값은 제거)
  • NATURAL JOIN
    • A 테이블과 B 테이블에서 같은 이름을 가진 컬럼들이 모두 동일한 데이터를 가지고 있을 경우 JOIN이 되는 방식이다.
    • SQL Server(MSSQL)에서는 지원하지 않는다.
    • Oracle의 경우 USING 조건절을 사용하여 같은 이름을 가진 컬럼중 원하는 컬럼만 JOIN에 사용할 수도 있다.
    • 단, SELECT 절에서 USING 절로 정의된 컬럼 앞에는 별도의 ALIAS나 테이블명을 붙이지 않아야 한다.
  • CROSS JOIN
    • 예선 수학 시간에 경우의 수에 대해 배운 적이 있을 것이다.
    • 비슷한 맥락으로 CROSS JOIN은 A 테이블과 B 테이블 사이에 JOIN 조건이 없는 경우, 조합할 수 있는 모든 경우를 출력하는 방식이다.
    • 다른 말로 Cartesian Product라고 표현하기도 한다.

문제 풀이중 팁

  • NULL과의 연산 결과는 False이므로 조건값이 늘 거짓이 되어 아무 데이터도 출력되지 않는다. 
  • CASE 문에서 ELSE 뒤의 값이 DEFAULT 값이 되고 별도의 ELSE가 없을 경우 NULL 값이 DEFAULT 값이 된다.
  • 나누기 연산을 할때 0으로 나누려하면 에러가 발생한다.
  • NATURAL JOIN은 공통 컬럼 앞에 OWNER 명을 붙이면 에러가 발생한다.
  • ALIAS를 별도로 지정해주지 않으면 컬럼명이 대문자로 출력된다.
  • ORDER BY 절에는 컬럼명을 명시해줄 수도 있고 SELECT 절에 기술된 컬럼의 순서를 숫자로 명시해줄 수도 있다.
  • AVG, MAX 함수는 각각 NULL 값을 제외하고 계산된다.
  • HAVING 절은 주로 GROUP BY 절 뒤에 오면서 집계 데이터에 대한 조건을 부여하지만 테이블 전체가 한 개의 그룹이 되는 경우 HAVING만 단독으로 사용할 수 있다.

정규화(Nomalization)

  • 데이터 정합성(데이터의 정확성과 일관성을 유지하고 보장)을 위해 엔터티를 작은 단위로 분리하는 과정이다.
  • 정규화를 할 경우 데이터 조회성능은 처리조건에 따라 향상되는 경우도 있고 저하되는 경우도 있다.
  • 일반적으로 입력, 수정, 삭제 성능은 향상된다.

 

  • 제1 정규형
    • 모든 속성은 반드시 하나의 값만 가져야 한다. (Table 1)
    • 유사한 속성이 반복되는 경우도 1차 정규화 대상이 된다.(Table2)
    • 하나의 속성이 다중값을 가지는 경우 데이터를 꺼내 쓸 때 불필요한 Split을 사용해야 하는 번거로움이 발생한다.
    • 한 엔터티 내 유사한 속성이 반복되는 경우는 데이터가 늘어날 때 공간낭비가 발생할 여지가 있다.

Table 1

이름 생년월일 직업
이지은 1993.05.16 배우, 가수, 작곡가

이름 생년월일
이지은 1993.05.16
이름 직업
이지은 배우
이지은 가수
이지은 작곡가

Table 2

이름 생년월일 사이트1 사이트2
이지은 1993.05.16 인스타그램 페이스북
김향기 2000.08.09 인스타그램 싸이월드

이름 생년월일
이지은 1993.05.16
김향기 2000.08.09
이름 사이트
이지은 인스타그램
이지은 페이스북
김향기 인스타그램
김향기 싸이월드
  • 제2 정규형
    • 엔터티의 모든 일반속성은 반드시 모든 주식별자에 종속되어야 한다.(Tabel 3)

Tabel 3.

주문번호 음료코드 주문수량 음료명
1234567890 A123 2 아메리카노
1234567891 A124 3 라떼
1234567892 A125 1 카푸치노

주문번호 음료코드 주문수량
1234567890 A123 2
1234567891 A124 3
1234567892 A125 1
음료코드 음료명
A123 아메리카노
A124 라떼
A125 카푸치노
  • 제3 정규형
    • 주식별자가 아닌 모든 속성 간에는 서로 종속될 수 없다.
    • 일반속성이 다른 일반속성에 종속된 경우에 제3 정규형을 적용한다. (Table 4)

Table 4

일렬번호 이름 생년월일 소속사코드 소속사명
1 이지은 1993.05.16 A1001 EDAM엔터테인먼트
2 김향기 2000.08.09 B1004 지킴엔터테인먼트

일렬번호 이름 생년월일 소속사코드
1 이지은 1993.05.16 A1001
2 김향기 2000.08.09 B1004
소속사코드 소속사명
A1001 EDAM엔터테인먼트
B1004 지킴엔터테인먼트

 

주의사항

  • 과유불급, 지나친 정규화는 오히려 성능 저하를 일으킬 수 있다.
  • 정보를 얻기 위해 여러 번의 JOIN이 불가피한 경우 반정규화를 통해 성능을 개선하여야 한다.

반정규화(De-Nomalization)

  • 데이터 조회 성능을 향상시키기 위해 데이터의 중복을 허용하거나 데이터를 그룹핑하는 과정이다.
  • 조회 성능은 향상될 수 있으나 입력, 수정, 삭제 성능은 저하될 수 있으며 데이터 정합성 이슈가 발생할 수 있다.
  • 반정규화 과정은 정규화가 끝난 후 거치게 되며 정규화와 마찬가지로 일정한 룰이 존재한다.

테이블 반정규화

테이블 병합 1:1 관계 테이블 병합
1:M 관계 테이블 병합
슈퍼 서브 타입 테이블 병합
테이블 분할 테이블 수직 분할(속성 분할)
테이블 수평 분할(인스턴스 분할, 파티셔닝)
테이블 추가 중복테이블 추가
통계테이블 추가
이력테이블 추가
부분테이블 추가
  • 테이블 병합
    • 업무 프로세스상 JOIN이 필요한 경우가 많아 테이블을 통합하는 것이 성능 측면에서 유리할 경우 고려한다.
    • 1:M 관계 테이블 병합의 경우 1쪽에 해당하는 엔터티의 속성 개수가 많으면 병합했을 경우 중복 데이터가 많아지므로 테이블 병합에 적절하지 못하다.
  • 테이블 분할
    • 테이블 수직 분할 : 엔터티의 일부 속성을 별도의 엔터티로 분할 (1:1 관계 성립)
    • 테이블 수평 분할:  엔터티의 인스턴스를 특정 기준으로 별도의 엔터티로 분할(파티셔닝)
      • 파티션 기능을 사용하여 데이터를 물리적으로 분리 → 관계가 없는 다수의 테이블이 생성된다.
  • 테이블 추가
    • 중복 테이블 추가: 데이터의 중복을 감안하더라도 성능상 반드시 필요하다고 판단되는 경우 별도의 엔터티를 추가한다.
      • 단순히 같은 데이터를 여러 테이블에 저장하는 것을 데이터 정합성에 위배되는 상황을 발생시킬 수 있다.
    • 통계 테이블 추가
      • Ex. 월매출 통계치를 미리 계산하여 저장
    • 이력 테이블 추가
      • Ex. 과거의 상품가격에 대한 데이터를 관리
    • 부분 테이블 추가
      • Ex. 회원 대상 메일 발송건이 다량으로 생기는 경우 메일 발송에 필요한 정보만 부분 테이블로 생성

칼럼 반정규화

  • 중복 컬럼 추가
    • 업부 프로세스상 JOIN이 필요한 경우가 많아 컬럼을 추가하는 것이 성능 측면에서 유리할 경우 고려한다.
  • 파생 컬럼 추가
    • 프로세스 수행 시 부하가 염려되는 계산값을 미리 컬럼으로 추가하여 보관하는 방식으로 상품의 재고나 프로모션 적용 할인가 등이 이에 해당할 수 있다.
  • 이력 테이블 컬럼 추가
    • 대량의 이력 테이블을 조회할 때 속도가 느려질 것을 대비하여 조회 기준이 될 것으로 판단되는 컬럼을 미리 추가해 놓는 방식이다. 최신 데이터 여부 등이 이에 해당할 수 있다.

관계 반정규화(중복관계 추가)

  • 업무 프로세스상 JOIN이 필요한 경우가 많아 중복 관계를 추가하는 것이 성능 측면에서 유리할 경우 고려한다.

 

트랜잭션(Transaction)

  • 데이터를 조작하기 위한 하나의 논리적인 작업 단위이다.

NULL이란?

  • NULL은 존재하지 않음, 즉 값이 없음을 의미한다.
  • NULL ≠ 0, 데이터가 입력되지 않은 것이다.
  • SQL NULL 처리 방식 (Table 5)
    • SELECT 수입 - 지출 FROM Table 5
      • 가로 연산: NULL이 포함되어 있으면 결과 값은 NULL이 된다. → NULL
    • SELECT SUM(수입) FROM Table 5
      • 세로 연산: 다른 인스턴스의 데이터와 연산할 때는 NULL 값을 제외한다. → 0

Table 5.

이름 수입 지출
강산 0 10
지원 NULL 20

※ 추가 정보 (문제 풀이 중 나온 개념 정리)

성능 데이터 모델링의 순서

  • 데이터 모델이 맞게 정규화를 수행한다
  • 데이터베이스의 용량 및 트랜잭션 유형을 파악하여 성능 저하를 일으키는 부분이 없는지 검토한다.
  • 용량과 트랜잭션 유형에 맞게 반정규화를 수행한다.
  • 성능 향상을 위한 이력모델의 조정, PK/FK 조정, 슈퍼/서브타입 조정 등을 수행한다.
  • 데이터 모델의 성능을 검증한다.

트랜잭션

  • 트랜잭션은 데이터를 조작하기 위한 논리적인 작업 단위로, 데이터 모델로 표현할 수 이쓰며 데이터는 트랜잭션 범위로 묶일 수 있다.
  • 트랜잭션은 하나의 커밋 단위로 묶여야 한다.

NULL

  • ㉮ WHERE COL IS NULL 조건과 ㉯ WHERE COL = NULL 조건은 다르다.
  • ㉮ 조건은 값이 NULL인 행을 반환한다.
  • ㉯ 조건의 결과는 항상 False이므로 아무 행도 반환하지 않는다.

집계함수

COL1 COL2
10 NULL
NULL 15
30 25
  • SELECT COUNT(COL1)*10 FROM TABLE;
    • NULL을 제외하고 계산되어 2*10 = 20
  • SELECT SUM(COL1+COL2)/4 FROM TABLE;
    • NULL과 사칙연산 결과는 제외되어 55/4 = 13.75
  • SELECT SUM(COL2)/2 FROM TABLE;
    • NULL을 제외하고 계산되어 40/2 = 20
  • SELECT AVG(COL1) FROM TABLE;
    • NULL을 제외하고 계산되어 40/2 = 20

정규화

  • 1차 정규화
    • 원자값이 아닌 도메인을 분해한다.
  • 2차 정규화
    • 부분 함수 종속성을 제거한다.
  • 3차 정규화
    • 이행 함수 종속성을 제거한다.
  • 4차 정규화
    • 다중값 종속성을 제거한다.

이력 테이블 추가

  • 이력 테이블 컬럼 추가는 대량의 이력 테이블을 조회할 때 속도가 느려질 것을 대비하여 조회 기준이 될 것으로 판단되는 컬럼을 미리 추가해 놓는 방식이다. 
  • Ex. 최신 가격 여부 컬럼 추가 등

슈퍼-서브 타입

  • 공통 속성을 조회하는 빈도수가 개별 속성을 조회하는 빈도수보다 높을 경우 공통 속성과 개별속성을 별도로 관리하는 슈퍼-서브 타입의 설계가 적절하다.

중복 관계 추가

  • 반정규화 기법 중 하나로 데이터 무결성을 깨뜨릴 위험성이 없어 데이터 처리 성능을 향상시킬 수 있는 기법이다.
  • 테이블 반정규화는 데이터의 무결성을 깨트릴 위험성을 가지고 있다.

모델링이란?

  • 현실 세계에서 일어날 수 있는 다양한 현상에 대해 일정한 표기법에 의해 표기해 놓은 모형이라 할 수 있다.
  • tip: 데이터 베이스의 모델링은 '현실 세계를 단순화하여 표현하는 기법'이다.

모델링이 갖춰야 할 조건

  • 현실세계를 반영해야 한다.
  • 단순화하여 표현해야 한다.
  • 관리하고자 하는 데이터를 모델로 설계한다.

모델링의 특징

  • 추상화(Abstraction): 현실 세계를 일정한 형식으로 표현하는 것이다. 즉, 아이디어나 개념을 간략하게 표현하는 과정이다.
  • 단순화(Simplification): 복잡한 현실 세계를 정해진 표기법으로 단순하고 쉽게 표현한다는 의미이다.
  • 명확화(Clarity): 불분명함을 제거하고 명확하게 해석할 수 있도록 기술한다는 의미이다.
  • tip: 데이터베이스의 모델링은 '현실세계를 추상화, 단순화, 명확화하기 위해 일정한 표기법에 의해 표현하는 기법'이다.

모델링의 세 가지 관점

  • 데이터 관점(What, Data): 데이터 위주의 모델링이라고 할 수 있다. 어떤 데이터들이 업무와 얽혀있는지, 그리고 그 데이터 간에는 어떤 관계가 있는지에 대해서 모델링하는 방법이다.
  • 프로세스 관점(How, Process): 프로세스 위주의 모델링이라고 할 수 있다. 이 업무가 실제로 처리하고 있는 일은 무엇인지 또는 앞으로 처리해야 하는 일은 무엇인지를 모델링하는 방법이다.
  • 데이터와 프로세스의 상관 관점(Data vs. Process, Interaction): 데이터와 프로세스의 관계를 위주로 한 모델링이라고 할 수 있다. 프로세스의 흐름에 따라 데이터가 어떤 영향을 받는지를 모델링하는 방법이다.

모델링의 세 가지 단계

  • 개념적 데이터 모델링(Conceptual Data Modeling): 전사적 데이터 모델링 수행 시 행해지며 추상화 레벨이 가장 높은 모델링이다. 이 단계에서는 업무 중심적이고 포괄적인 수준의 모델링이 진행된다.
  • 논리적 데이터 모델링(Logical Data Modeling): 재사용정이 가장 높은 모델링으로 데이터베이스 모델에 대한 Key, 속성, 관계 등을 모두 표현하는 단계이다.
  • 물리적 데이터 모델링(Physical Data Modeling): 실제 데이터베이스로 구현할 수 있도록 성능이나 가용성등의 물리적인 성격을 고려하여 모델을 표현하는 단계이다.

데이터의 독립성

  • 3단계 스키마 구조(ANSI-SPARC에서 정의함)
  • 목적: 데이터베이스에 대한 사용자들의 관점과 데이터베이스가 실제로 표현되는 물리적인 방식을 분리하기 위함
  • 예시: 사용자는 데이터를 볼 수 있는 뷰만 제공 받으면됨 / DBA 입장에서는 App에 영향을 주지 않고 데이터베이스의 구조를 변경할 수 있어야 독립성이 보장됨
    • 외부 스키마(External Schema)
      • 사용자의 관점: Multiple User's View 단계로 각 사용자가 보는 데이터베이스의 스키마를 정의한다.
    • 개념 스키마(Conceptual Schema)
      • 통합된 관점 : Community View of DB 단계로 모든 사용자가 보는 데이터베이스의 스키마를 통합하여 전체 데이터베이스*를 나타내는 것이다. 데이터베이스에 저장되는 데이터들을 표현하고 데이터들 간의 관계를 나타낸다.
    • 내부 스키마(Internal Schema)
      • 물리적인 관점: Pysical Representation 단계로 물리적인 저장 구조를 나타낸다. 실질적인 데이터의 저장 구조나 컬럼 정의, 인덱스 등이 포함된다.
  • 3단계 스키마 구조가 보장하는 독립성
  • 이유: 데이터베이스에 대한 사용자들의 관점과 데이터베이스가 실제로 표현되는 물리적인 방식을 분리하여 독립성을 보장하기 위한 것
    • 논리적 독립성: 개념 스키마가 변경되어도 외부 스키마는 영향받지 않는다.
    • 물리적 독립성: 내부 스키마가 변경되어도 외부/개념 스키마는 영향받지 않는다.

ERD(Entity Relationship Diagram)

  • ERD 표기 방식
    • Peter Chen : 주로 대학교재에서 사용하는 표기법으로 실무에서 사용하는 경우는 드물다.
    • IDEFIX(Intergration Definition for Information Modeling): 실무에서 사용하는 경우도 있으며 ERWin에서 사용되는 모델이다.
    • IE/Crow's Foot: 까마귀발 표기법이라고도 부르며 가장 많이 사용한다. ERWin, ERStudio에서 사용되는 모델이다.
    • Min-Max/ISO: 각 엔터티의 참여도를 좀 더 상세하기 나타내는 표기법이다.
    • UML: 소프트웨어 공학에서 주로 사용되는 모델이다.
    • Case Method/Barker: Oracle에서 상요되는 모델로 Crow's Foot과 비슷하다.
  • IE/Crow's Foot 표기법 (공부하는 책에서 사용하는 표기법)
  • 이미지 출처: https://ppomelo.tistory.com/51
  • 실선: 식별자 관계
  • 점선: 비식별자 관계
  • ERD 작성 순서
  • 어떤 표기법을 사용하든 ERD를 작성하는 순서는 공통된 룰이며, 다음의 표기 순서를 따른다.
    • 엔터티를 도출하고 그린다.
    • 엔터티를 적잘하기 배치한다.
    • 엔터티 간의 관계를 설정한다
    • 관계명을 기입한다.
    • 관계참여도를 기입한다.
    • 관계의 필수/선택 여부를 기입한다.

엔터티란?

  • 데이터베이스에서 엔터티는 식별이 가능한 객체라는 의미를 가진다.
  • 쉽게 말해서 엔터티는 업무에서 쓰이는 데이터를 용도별로 분류한 그룹이라고 할 수 있다.
  • 각각의 엔터티는 자신을 상세하기 나타내기 위한 속성을 가진다 (Ex. '회원'이라는 엔터티는 '아이디', '비밀번호', '이름', '주소'등의 속성을 가질 수 있다.)
  • tip
    • 엔터티: Table
    • 인스턴스: Row
    • 속성: column

엔터티의 특징

  • 업무에서 쓰이는 정보여야 함
  • 유니크함을 보장할 수 있는 식별자가 있어야 함: Ex. 별도의 상품코드를 발번하여 인스턴스를 식별하기 설계
  • 2개 이상의 인스턴스를 가지고 있어야 함: Ex. '유저'라는 엔터티가 하나이고 앞으로도 하나라면 굳이 엔터티로 만들 필요가 없다.
  • 반드시 속성을 가지고 있어야 함: 속성이 없는 엔터티는 깡통 휴대폰과 같다. 엔터니는 반드시 자신을 상세하기 나타낼 수 있는 속성을 가지고 있어야 한다.
  • 다른 엔터티와 1개 이상의 관계를 가지고 있어야 함

엔터티의 분류

  • 유형 vs 무형
유형 엔터티 물리적인 형태 존재, 안정적, 지속적
Ex. 상품, 회원
개념 엔터티 물리적인 형태 없음, 개념적
Ex. 부서, 학과 
사건 엔터티 행위를 함으로써 발생, 빈번함, 통계 자료로 이용가능
Ex. 주문, 이벤트 응모
  • 발생 시점
기본 엔터티 독립적으로 생성됨, 자식 엔터티를 가질 수 있음
Ex. 상품, 회원
중심 엔터티 기본 엔터티로부터 파생, 행위 엔터티 생성
Ex. 주문
행위 엔터티 2개 이상의 엔터티로부터 파생
Ex. 주문 내역, 이벤트 응모 이력
  • tip: 엔터티의 이름을 정할 때 주의할 점
    • 업무에서 실제로 쓰이는 용어 사용
    • 한글을 약어를 사용하지 않고 영문은 대문자로 표기
    • 단수 명사로 표현하고 띄어쓰기는 하지 않음
    • 다른 엔터티와 의미상으로 중복될 수 없음(주문, 결제 엔터티는 중복될 수 있음)
    • 해상 엔터티가 갖고 있는 데이터가 무엇인지 명확하게 표현

속성이란?

  • 사물이나 개념의 특징을 설명해줄 수 있는 항목들을 속성이라고 부른다.
  • 속성은 의미상 더 이상 쪼개지지 않는 레벨이어야 한다.
  • 속성을 프로세스에 필요한 항목이어야 한다.

속성값

  • 각각의 속성은 속성값을 가진다.
  • 속성값은 엔터티에 속한 하나의 인스턴스를 구체적으로 나태내주는 데이터라고 볼 수 있다.
  • 속성은 한 개의 속성값만 가질 수 있다. 만약 하나의 속성이 여러 개의 속성값을 갖는 경우 별도의 엔터티로 분리하는 것이 바람직하다.

엔터티, 인스턴스, 속성, 속성값의 관계

  • 엔터티 ⊃ 인스턴스 ⊃ 속성의 관계가 성립한다.
  • 한 개의 엔터티는 두 개 이상의 인스턴스를 갖는다.
  • 한 개의 인스턴스는 두 개 이상의 속성을 갖는다.
  • 한 개의 속성은 하나의 속성값을 갖는다.

분류

  • 특성에 따른 분류
기본속성(Basic Attribute) 업무 프로세스 분석을 통해 바로 정의가 가능한 속성
설계속성(Designed Attribute) 업무에 존재하지는 않지만 설계하다 보니 필요하다고 판단되어 도줄해낸 속성
파생속성(Derived Attribute) 다른 속성의 속성값을 계산하거나 특정한 규칙으로 변형하여 생성한 속성
  • 기본속성
    • 엔터티의 가장 일반적인 속성으로 업무 프로세스 분석을 통해 바로 정의가 가능한 속성들이 여기에 속한다.
    • 엔터티의 가장 많은 퍼센티지를 차지한다.
    • 설계속성과, 파생속성을 제외한 모든 속성이 기본 속성에 해당한다.
  • 설계속성
    • 업무에 존재하지는 않지만 설계 과정에서 합리적인 모델링을 위해 만들어진 속성이다. 
    • Ex. 유니크함을 보장하기 위한 학생 개개인에게 학번이라는 고유번호를 할당하는 경우
  • 파생속성
    • 다른 속성으로부터 파생된 속성을 의미하는 것으로 계산된 값이나 가공된 값이 이에 속한다.
    • 파생속성을 설계할  경우 반드시 데이터의 정합성이 고려되어야 한다. (누락데이터 고려)
    • Ex. 주문 상품의 재고를 계산하여 속성으로 가지는 경우
  • 구성방식에 따른 분류
PK(Primary Key)속성 엔터티의 인스턴스들을 식별할 수 있는 속성
FK(Foreign Key)속성 다른 엔터티의 속성에서 가져온 속성
일반 속성 PK, FK를 제외한 나머지 속성
  • PK속성
    • 엔터티에 속한 각 인스턴스에 유니크함을 부여하는 속성이다.
    • Ex. 상품 엔터티의 상품코드, 학생 엔터티의 학번, 직원 엔터티의 사번 등
  • FK속성
    • 다른 엔터티와 관계를 맺게 해주는 매개체 역할을 하는 속성이다.
    • Ex. 직원 엔터티의 부서 코드, 학생 엔터티의 학과코드, 회원 엔터티의 회원등급코드 등
  • 일반속성
    • PK, FK를 제외한 나머지 속성을 일반속성이라고 부른다
    • Ex. 상품엔터티의 상품명, 가격 / 학생 엔터티의 이름, 생년월일 등

도메인

  • 속성이 가질 수 있는 속성값의 범위를 도메인이라고 한다.
  • Ex. 우편번호는 다섯 자리의 숫자라는 범위를 가지고 있고 이것은 엔터티를 정의할 때 데이터 타입과 크기로 나타낼 수 있다.

용어사전

  • 하나의 데이터베이스에서 같은 의미를 가진 데이터가 엔터티마다 다른 명으로 정의된다면 혼란을 초래한다.
  • 설계 시 용어사전을 두고 각 엔터티에 공통된 룰로 적용하는 것이 바람직하다.

관계란?

  • 엔터티와 엔터티와의 관계를 의미한다
  • 존재관계
    • 엄마와 아기처럼 존재 자체로 연관성이 있는 관계를 의미한다.
    • Ex. 직원과 부서, 학생과 학과
  • 행위관계
    • 특정한 행위를 함으로써 연관성이 생기는 관계를 의미한다.
    • Ex. 회원과 주문, 학생과 출석부
  • 표기법
관계명(Mevership) 관계의 이름
관계차수(Cardinality) 관계에 참여하는 수
관계선택사양(Optionality) 필수인지 선택인지 여부
  • 관계명
    • 엔터티와 엔터티가 어떠한 관계를 맺고 있는지를 나타내주는 문장이다.
    • 모든 관계는 두 개의 관계명을 가지고 있는데 이유는 각 엔터티의 관점에서 관계명을 하나씩 가지기 때문이다.
    • 관계명은 반드시 명확한 문장으로 표현해야 하며 현재형이여야 한다.
  • 관계차수 각 엔터티에서 관계에 참여하는 수를 의미하여 일반적으로 1:1, 1:M, M:N 형식으로 구분할 수 있다.
  • 관계선택사양
    • 이 관계가 필수요소인지 선택사항인지 나타내는 말이다.
필수적 관계 참여자가 반드시 존재해야 하는 관계
선택적 관계 참여자가 없을 수도 있는 관계

식별자란?

  • 모든 엔터티는 인스턴스를 가지고 있고 인스턴스는 속성으로 자신의 특성을 나타낸다고 하였다. 식별자는 이런 속성 중에 각각의 인스턴스를 구분 가능하게 만들어주는 대표격인 속성을 의미한다.
  •  Ex. 학번, 군번, 사번

주식별자

  • 주식별자는 기본키, PK(Primary Key)에 해당하는 속성이다.
  • 하나의 속성이 주식별자가 될 수도 있고 여러 개의 속성이 주식별자가 될 수도 있다.
유일성 각 인스턴스에 유니크함을 부여하여 식별이 가능하도록 한다.
최소성 유일성을 보장하는 최소 개수의 속성이어야 한다.
불변성 속성값이 되도록 변하지 않아야 한다.
존재성 속성값이 NULL일 수 없다.

 

분류

  • 식별자를 분류하는 방식은 여러가지로 나뉜다. 
  • 대표성 여부, 스스로 생성되었는지 여부, 단일 속성의 여부, 대체 여부가 분류의 기준이 된다.
  • 대표성여부
주식별자(Primary Identifier) - 유일성, 최소성, 불변성, 존재성을 가진 대표 식별자
- 다른 엔터티와 참조 관계로 연결
보조식별자(Alternate Identifier) - 인스턴스를 식별할 수는 있지만 대표 식별자가 아님
- 다른 엔터티와 참조 관계로 연결되지 않음
  • 스스로 생성되었는지 여부
내부식별자(Internal Identifier) 엔터티 내부에서 스스로 생성된 식별자
외부식별자(Foreign Identifier) 다른 엔터티에서 온 식별자, 다른 엔터티과 연결고리 역할
  • 단일 속성의 여부
단일식별자(Single Identifier) 하나의 속성으로 구성된 식별자
복합식별자(Composite Identifier) 두 개 이상의 속성으로 구성된 식별자
  • 대체 여부
원조식별자(Original Identifier) 업무 프로세스에 존재하는 식별자. 가공되지 않은 원래의 식별자(본질식별자)
대리식별자(Surrogate Identifier) 주식별자의 속성이 두 개 이상인 경우 그 속성들을 하나로 묶어서 사용하는 식별자(인조식별자)

식별자  관계 vs 비식별자 관계

  • 식별자 관계(Identifier Relationship)
    • 부모 엔터티의 식별자가 자식 엔터티의 주식별자가 되는 관계이다.
    • 주식별자는 반드시 존재해야 하므로 부모 엔터티가 있어야 생성 가능하며 단일식별자인지 복합식별자인지에 따라 1:1, 1:M이 결정된다.
  • 비식별자 관계(Non-Identifier Relationship)
    • 부모 엔터티의 식별자가 자식 엔터티의 주식별자가 아닌 일반 속성이 되는 관계이다.
    • 일반 속성의 속성값은 NULL이 될 수 있으므로 부모 엔터티가 없는 자식 엔터티 생성이 가능하고 부모 엔터티가 삭제될 수도 있다.
# if문은 왜 필요할까?

    # "돈이 있으면 택시를 타고, 돈이 없으면 걸어 간다."
    # 위와 같은 상황을 파이썬에서는 다음과 같이 표현할 수 있다.

# if문의 기본 구조
    # if 조건문: 
    #     수행할 문장1
    #     수행할 문장2
    #     ...
    # else:
    #     수행할 문장A
    #     수행할 문장B
    #     ...
    # 들여쓰기에 주의 하자 (4 spacebar = 1 tab)

# 비교연산자
    # 비교연산자	설명
    # x < y	x가 y보다 작다
    # x > y	x가 y보다 크다
    # x == y	x와 y가 같다
    # x != y	x와 y가 같지 않다
    # x >= y	x가 y보다 크거나 같다
    # x <= y	x가 y보다 작거나 같다

# 연산자 사용예시

x = 3
y = 2
x > y # True
x < y # False

money = 2000
if money >= 3000:
     print("택시를 타고 가라")
else:
     print("걸어가라")

# 걸어가라

# and, or, not

# 연산자	설명
# x or y	x와 y 둘중에 하나만 참이어도 참이다
# x and y	x와 y 모두 참이어야 참이다
# not x	x가 거짓이면 참이다

money = 2000
card = True
if money >= 3000 or card:
     print("택시를 타고 가라")
else:
     print("걸어가라")

# 택시를 타고 가라

# x in s, x not in s

# in	not in
# x in 리스트	x not in 리스트
# x in 튜플	x not in 튜플
# x in 문자열	x not in 문자열

# 예시
1 in [1, 2, 3]     # True
1 not in [1, 2, 3] # False

pocket = ['paper', 'cellphone', 'money']
if 'money' in pocket:
    print("택시를 타고 가라")
else:
    print("걸어가라")

# 조건문에서 아무 일도 하지 않게 설정하고 싶다면?
# "주머니에 돈이 있으면 가만히 있고 주머니에 돈이 없으면 카드를 꺼내라."
# 이럴 때 사용하는 것이 바로 pass이다. 위 예를 pass를 적용해서 구현해 보자.
pocket = ['paper', 'money', 'cellphone']
if 'money' in pocket:
     pass 
else:
     print("카드를 꺼내라")

# 다양한 조건을 판단하는 elif
# if와 else만으로는 다양한 조건을 판단하기 어렵다. 이런 복잡함을 해결하기 위해 파이썬에서는 다중 조건 판단을 가능하게 하는 elif를 사용한다.
pocket = ['paper', 'cellphone']
card = True
if 'money' in pocket:
     print("택시를 타고가라")
elif card: 
     print("택시를 타고가라")
else:
     print("걸어가라")

# if문을 한 줄로 작성하기
# : 뒤에 바로 적어주기
pocket = ['paper', 'money', 'cellphone']
if 'money' in pocket: pass
else: print("카드를 꺼내라")

# 조건부 표현식
#조건문이 참인 경우 if 조건문 else 조건문이 거짓인 경우
score = 59
message = "success" if score >= 60 else  "failure"# 이렇게 대입방식만 가능한 건가?
print(message)
# Q1. 홍길동 씨의 과목 별 점수는 다음과 같다. 홍길동 씨의 평균 점수를 구해보자
# 과목 점수
# 국어 80
# 영어 75
# 수학 55

# answer
points = [80,75,55]
avg = sum(points) / len(points)
avg

# Q2. 자연수 13 이 홀수인지 짝수인지 판별할 수 있는 방법에 대해 말해 보자.
# answer
num = 13
if num % 2 == 0:
    print("짝수")
else:
    print("홀수")

# Q3. 홍길동 씨의 주민등록번호는 881120-1068234이다. 홍길동 씨의 주민등록번호를 연월일(YYYYMMDD) 부분과 그 뒤의 숫자 부분으로 나누어 출력해 보자.
id = "881120-1068234"
id = id.split('-')
print("앞자리: {0}".format(id[0]))
print("뒷자리: {0}".format(id[1]))

# Q4. 주민등록번호 뒷자리의 맨 첫 번째 숫자는 성별을 나타낸다. 주민등록번호에서 성별을 나타내는 숫자를 출력해 보자.
pin = "881120-1068234"
pin = pin.split('-')
print(pin[1][0])

# Q5. 다음과 같은 문자열 a:b:c:d가 있다. 문자열의 replace 함수를 사용하여 a#b#c#d로 바꿔서 출력해 보자.
a = "a:b:c:d"
a.replace(":","#")

# Q6. [1, 3, 5, 4, 2] 리스트를 [5, 4, 3, 2, 1]로 만들어 보자.
l1 = [1, 3, 5, 4, 2]
l1.reverse()
l1

# Q7. ['Life', 'is', 'too', 'short'] 리스트를 Life is too short 문자열로 만들어 출력해 보자.
l1 = ['Life', 'is', 'too', 'short']
str1 = ' '.join(l1)
str1

# Q8. (1,2,3) 튜플에 값 4를 추가하여 (1,2,3,4)를 만들어 출력해 보자.
tup1 = (1,2,3)
tup2 = (4,) # ,를 안넣어줘서 에러가 발생했었다.
tup1 + tup2

# Q9. 다음과 같은 딕셔너리 a가 있다.
a = dict()
a
# 다음 중 오류가 발생하는 경우를 고르고, 그 이유를 설명해 보자.
a['name'] = 'python'
a[('a',)] = 'python'
a[[1]] = 'python' # 딕셔너리의 key 값으로 가변적인 list는 사용할 수 없다.
a[250] = 'python'
a

# Q10. 딕셔너리 a에서 'B'에 해당되는 값을 추출해 보자.
a = {'A':90, 'B':80, 'C':70}
a.pop('B')

# Q11. a 리스트에서 중복 숫자를 제거해 보자.
a = [1, 1, 1, 2, 2, 3, 3, 3, 4, 4, 5]
a = set(a)
a

# Q12. 파이썬은 다음처럼 동일한 값에 여러 개의 변수를 선언할 수 있다. 
# 다음과 같이 a, b 변수를 선언한 후 a의 두 번째 요솟값을 변경하면 b 값은 어떻게 될까? 
# 그리고 이런 결과가 오는 이유에 대해 설명해 보자.
a = b = [1, 2, 3]
a[1] = 4
print(b)
# 변수를 생성할 때 메모리 주소를 넘겨주기 때문에 a, b는 같은 값을 참조하고 있는 것이다.
# 따라서 a, b 둘 중 아무나거 바꿔도 둘다 반영된다.
# 변수는 어떻게 만들까? 앞에서 이미 변수를 사용해 왔다.
a = 1
b = "python"
c = [1,2,3]

# 변수란?
# 파이썬에서 사용하는 변수는 객체를 가리키는 것이라고도 말할 수 있다.
# 객체란 우리가 지금껏 보아 온 자료형과 같은 것을 의미하는 말이다.
a = [1,2,3]
# 위코드의 의미는 리스트 자료형(객체)이 자동으로 메모리에 생성되고 변수 a는 리스트가 저장된 메모리의 주소를 가리키게 된다.
id(a) # 메모리의 주소는 id() 함수로 확인할 수 있다.

# 리스트를 복사하고자 할 때
b = a
id(a)
id(b)
a is b
# 주소값이 동일하다 = 동일한 객체를 가리키고 있다라는 것을 확인 할 수 있다.
a[1] = 4
a # [1, 4, 3]
b # [1, 4, 3]
# a 변수만 변경했는데 b 변수도 변경된 것으로 같은 주소값을 가르키고 있다는 것을 확인 할 수 있다.

# b 변수를 생성할 때 a 변수의 값을 가져오면서 a와는 다른 주소를 가리키도록 만들기
# 1. [:] 이용
a = [1,2,3]
b = a[:]
a[1] = 4
a
b # a값이 변경되어도 b에 영향이 없는 것을 확인 할 수 있다.

# 2 copy 모듈 이용하기
from copy import copy
a = [1,2,3]
b = copy(a)
b is a # False를 반환함으로 다른 객체를 제대로 생성했음을 확인 할 수 있다.
a = [1, 2, 3]
b = a.copy() # 리스트 자료형의 자체 함수인 copy 함수를 사용해도 copy 모듈을 사용하는 것과 동일한다.
b is a

# 변수를 만드는 여러 가지 방법
a, b = ('python', 'life') # 튜플로 대입
a
b
[a, b, c] = ['python', 'life', 'good'] # 리스트로 대입
c
a = b = 'python' # 여러개의 변수에 같은 값 대입하기
# 불(bool) 자료형이란 참(True)과 거짓(False)을 나타내는 자료형이다.
a = True
b = False
type(a)
type(b)

# 불 자료형은 조건문의 반환 값으로도 사용된다.
1 == 1 # True
2 > 1  # True
2 < 1  # False

# 자료형의 참과 거짓
# "python"  True
# ""        False 
# [1,2,3]   True
# []        False  
# ()        False  
# {}        False
# 1         True  
# 0         False  
# None      False
# 문자열, 리스트, 튜플, 딕셔너리 등의 값이 비어 있으면 거짓이다.
# 숫자에서는 그 값이 0일 때 거짓이 된다.

# 사용 예시
a = [1, 2, 3, 4]
while a:
    print(a.pop())
# a 리스트에 비어있게 되기 전까지 print(a.pop())을 수행한다.

# 불 연산
bool("python")
bool('')
bool([1,2,3])
bool([])
bool(0)
bool(3)

+ Recent posts