데이터 생성, 조작과 변환

42418 단어 mysqlmysql

문자열, 숫자, 시간 데이터를 생성하고 변환하고 조작하는 법을 알아보자. (feat. 내장함수)

문자열 데이터 처리

문자열 데이터를 처리할 때는 문자 자료형 중 하나를 사용한다.

  • CHAR : 지정한 크기보다 문자열이 작으면 나머지 공간을 공백으로 채워주는 고정 길이 문자열 자료형
  • VARCHAR : 가변 길이 문자열 자료형
  • text 또는 clob : 매우 큰 가변 길이 문자열을 저장 (문서)
    • text - MySQL 및 SQL 서버
    • clob - 오라클 데이터베이스

데이터를 생성, 변환, 조작하는 법을 예시로 들기 위해 테이블을 하나 만들겠다.

CREATE TABLE string_tbl (
	char_fld CHAR(30)
	, vchar_fld VARCHAR(30)
	, text_fld text
);

문자열 생성

각 열에 값을 추가해보자.

INSERT INTO string_tbl (char_fld, vchar_fld, text_fld)
VALUES ('This is char data', 'This is varchar data', 'This is text data');

MySQL 6.0 이후 기본모드는 'strict' 모드이기 때문에, 자료형에 허용된 최댓값을 테이블에 넣으려고 하면 예외가 발생한다. 예를 들어 VARCHAR(30)이라고 지정한 열에 45자 이상의 문자를 넣으려고 한다면 예외가 발생할 것이다. 엔진이 예외를 발생시키는 대신 문자열을 자르고 경고를 발생하도록 하려면 ANSI 모드를 선택해야 한다.

현재 모드 확인하기

SELECT @@session.sql_mode ;

ANSI 모드로 변경하기

SET sql_mode = 'ansi' ;

VARCHAR 열에서 문자열이 잘리는걸 방지하는 제일 좋은 방법은 저장할 수 있는 가장 긴 문자열을 처리할 수 있을만큼, 충분히 높게 열의 최댓값을 설정하는 것이다.

작은 따옴표 포함

문자열은 작은 따옴표' ' 로 구분되기 때문에, don't나 I'm 처럼 작은 apostrophe가 쓰이는 곳에서 문자열이 끝난 것 처럼 판단될 가능성이 있다. 이럴 경우 문자열에 escape를 추가하면 된다.

이렇게.

UPDATE string_tbl 
SET text_fld = 'This string didn\'t work, but it does now';

특수 문자 포함

음..... 굳이 내가 사용할 것 같지 않은 내용이긴 하지만.
SELECT CHAR(97,98,99,100) 이런식으로 문자열을 검색할 수 있고, concat()char() 함수를 이용해서 danke schön 과 같은 문자열을 만들 수도 있다...... 특정 문자에 대한
ASCII 값을 찾고 싶으면 ascii() 함수를 써라..... 뭐 이런 내용이었다. 🙄 이게 왜 필요한건지 주변에 물어봤는데 암호학 어쩌고 얘기를 하는데 못알아듣겠어서 패스...

문자열 조작

테이블을 약간 수정해보자.

INSERT INTO string_tbl (char_fld, vchar_fld, text_fld)
VALUES ('This string is 28 characters', 'This string is 28 characters', 'This string is 28 characters');

테이블이 수정되었다.

숫자를 반환하는 문자열 함수

length() : 문자열의 문자 갯수를 보여준다.

SELECT 
	LENGTH (char_fld) char_length
	, LENGTH (vchar_fld) vchar_length
	, LENGTH (text_fld) text_length
FROM string_tbl;

MySQL는 조회할 때 char 데이터에서 공백을 제거하므로, 30 이 아닌 28로 결과값이 보여진다.

position() : 문자열 내에서 특정 문자열의 위치를 찾을 수도 있다.

SELECT 
	POSITION('characters' IN vchar_fld)
FROM string_tbl;


19번째에서 characters가 시작된다는 것을 보여준다.

locate() : 특정 위치의 문자부터 검색할 수도 있다.

vchar_fld 열의 5번째 문자에서 시작하는 문자열 is 의 위치를 검색하고 싶다면,

SELECT LOCATE('is', vchar_fld, 5)
FROM string_tbl ;

문장 맨앞의 'This'에서의 'is'는 제외되고 13번째에서 시작된다는 것을 보여준다.

strcmp() : 문자열의 위치를 비교할 수도 있다.

두개의 문자열을 인수로 받고 -1, 0, 1 중 하나로 결과가 나온다.

  • 정렬순서에서 첫번째 문자열이 두번째 문자열 에 오는 경우 : -1
  • 두개의 문자열이 동일한 경우 : 0
  • 정렬순서에서 첫번째 문자열이 두번째 문자열 에 오는 경우 : 1

예를 들어, abcd, QRSTUV, qrstuv, xyz 이렇게 4개가 있다고 하자.
STRCMP('abcd','xyz') 를 하면 abcd가 xyz보다 앞에 있으므로 -1이 나올 것이고,
STRCMP('xyz','qrstuv')를 하면 1이 나올 것이다.

이 함수는 대소문자를 구분하지 않으므로 STRCMP('QRSTUV', 'qrstuv')를 하면 0이 나온다.

like를 써서 문자열을 비교할 수도 있다. 이때 1(참), 0(거짓)으로 구분한다.

SELECT 
	name
	, name LIKE '%y' AS ends_in_y
FROM category ;

문자열을 반환하는 문자열 함수

concat() 함수

concat() 함수는 문자열에 문자를 추가하거나, 저장된 데이터를 대체할 때 유용하게 쓰인다.

  • 각 데이터 조각을 합쳐서 문자열을 만들때 사용한다.
  • 문자열을 반환하는 모든 표현식을 처리할 수 있다.
  • 숫자와 날짜를 문자열로 반환할 수도 있다. (아래 예시에서 date(create_date) 부분)
  • 문자열 중간에 문자를 추가하고나, 교체해야 할 때도 쓸 수 있다.

{이름_성}은 {언제부터} 우리의 고객이었다. 라는 문자열을 만들고 싶다고 가정해보자.

SELECT 
	CONCAT(first_name, ' ', last_name, ' has been a customer since', date(create_date)) AS customer_narrative
FROM customer ;

insert() 함수

4개 인수로 구성되어 있다.
원래 문자열, 시작 위치, 대체할 문자 개수, 대체 문자열

mysql> SELECT INSERT ('goodbye world', 9, 0, 'cruel') string;
+--------------------+
| string             |
+--------------------+
| goodbye cruelworld |
+--------------------+
1 row in set (0.00 sec)

→ 9번째에서 'cruel'이 삽입된다.

mysql> SELECT INSERT ('goodbye world', 1, 7, 'hello') string;
+-------------+
| string      |
+-------------+
| hello world |
+-------------+
1 row in set (0.00 sec)

→ 1부터 7개의 문자를 'hello'로 대체한다.

substr() 함수 : 문자열을 추출할 때

문자열에서 부분 문자열을 추출하고자 할 때 사용한다.

mysql> SELECT SUBSTR('동해물과백두산이마르고닳도록', 3, 4);
+------------------------------------------------------------+
| SUBSTR('동해물과백두산이마르고닳도록', 3, 4)               |
+------------------------------------------------------------+
| 물과백두                                                   |
+------------------------------------------------------------+
1 row in set (0.00 sec)

→ 3번째 문자열부터 4글자만 가져온다.

숫자 데이터 처리

산술 함수

특정 산술 연산을 수행할 수 있는 내장 숫자 함수들이 있다.

  • cos(𝑥) : 𝑥의 코사인 구하기
  • cot(𝑥) : 𝑥의 코탄젠트 구하기
  • ln(𝑥) : 𝑥의 자연로그 구하기
  • sin(𝑥) : 𝑥의 사인 구하기
  • sqrt(𝑥) : 𝑥의 제곱근 구하기
  • tan(𝑥) : 𝑥의 탄젠트 구하기
  • MOD(a,b) : a를 b로 나눈 나머지 구하기
  • pow(a,b) : a의 b 제곱근 구하기 → 컴퓨터 메모리는 2의 𝑥 제곱근 단위로 할당되기 때문에, 특정한 메모리의 바이트 수를 계산할 때 편리하다.
  • sign() : 인수의 부호 반환 ( 양수면 1, 음수면 -1, 0이면 0 )
  • abs() : 절대값 반환

숫자 자릿수 관리

부동소수점(Floating Point)이 뭐지...? 🙄

사람이 0~9을 가지고 숫자를 표현하는 반면에, 컴퓨터는 0과 1의 조합으로 이루어진 비트(bit)로 저장하고 연산한다. 그래서 실수(real number)를 컴퓨터가 표현하기 위해서 고정소수점 방식부동소수점 방식이 사용된다.
이 글이 그나마 꽤 쉽게 쓰여있어 부동소수점을 이해하는데 도움이 되었다.

ceil, floor, round, truncate 함수

부동소수점 숫자의 자리수를 제한할 때 이 4개의 함수를 사용하면 유용하다.

  • ceil() 함수 : 가장 가까운 정수로 올림 할 때 → ceil(72.445) = 73
  • floor() 함수 : 가장 가까운 정수로 내림 할 때 → floor(72.445) = 74
  • round() 함수 : 두 정수 사이의 중간점에서 반올림하거나 내림 할 때
    • 예1. ROUND(72.4999) = 72
    • 예2. ROUND(72.5) = 73
    • 예3. ROUND(72.5001) = 73
  • round() 함수는 소수점 자리수를 정할 수도 있다.
    • 예1. ROUND(72.0909, 1) = 소수점 1자리까지 반올림해라 = 72.1
    • 예2. ROUND(72.0909, 2) = 소수점 2자리까지 반올림해라 = 72.09
    • 예3. ROUND(72.0909, 3) = 소수점 3자리까지 반올림해라 = 72.091
  • truncate() 함수도 소수점 자리수를 지정할 수 있지만, 반올림하는 대신 원치 않는 숫자를 버린다
    • 예1. TRUNCATE(72.0909, 1) = 72.0
    • 예2. TRUNCATE(72.0909, 2) = 72.09
    • 예3. TRUNCATE(72.0909, 3) = 72.090

신기한 건, round()truncate() 모두 두번째 인수에 음수값을 허용한다.
예를 들어 10개 단위로만 구매할 수 있는 제품인데, 고객이 17개를 주문했을 때, 고객의 주문수량은 10=1개가 되어야 한다. 이때 truncate()함수를 이용해 계산할 수 있다.
참고 차원에서 round() 함수를 썼을 때의 결과값도 비교해보자.

mysql> SELECT ROUND(17, -1), TRUNCATE(17, -1);
+---------------+------------------+
| ROUND(17, -1) | TRUNCATE(17, -1) |
+---------------+------------------+
|            20 |               10 |
+---------------+------------------+
1 row in set (0.00 sec)

Signed 데이터 처리

예를 들어, 계좌 테이블이 아래와 같이 있다고 가정해보자.

이 테이블에서 은행 계좌의 현재 상태를 보여주는 보고서를 만들어보자.

SELECT account_id, SIGN(balance), ABS(balance)
FROM account ;
============================================
account_id|SIGN(balance)|ABS(balance)|
----------+-------------+------------+
       123|            1|      785.22|
       456|            0|         0.0|
       789|           -1|      324.22|

SIGN() 함수를 이용해 계좌 잔액이 음수이면 -1, 잔액이 0이면 0, 잔액이 양수이면 1을 반환했다.
ABS() 함수를 이용해 계좌 잔액의 절댓값을 반환했다.

시간 데이터 처리

시간대 처리

전세계의 시간대(time zone)는 24개의 가상 영역으로 나뉘어져 있다.
시간 기록의 공통적인 기준을 위해서 15세기 항해사들은 시계를 영국 그리니치의 시간대로 설정했다. 그리니치 표준시 또는 GMT로 알려진 시간대다. 오늘날 우리는 국제원자시(TAI)에 기반한 협정 세계표준시(UTC)라는 변형된 GMT를 사용한다. MySQL에서 utc_timestamp() 함수를 통해 현재 UTC 타임스탬프를 확인할 수 있다.

시간 데이터 생성

  • 기존 date, datetime 또는 time 열에서 데이터 복사
  • date, datetime 또는 time을 반환하는 내장 함수 실행
  • 서버에서 확인된 시간 데이터를 문자열로 표현 → 날짜 형식 지정에 사용되는 구성요소를 알아야한다.

시간 데이터의 문자열 표시

  • 예를 들어, datetime의 기본 형식은 YYYY-MM-DD HH:MI:SS이다.
  • 서버는 문자열을 기본 datetime 형식에 포함된 6개의 구성요소(년, 월, 일, 시, 분, 초)로 파싱해서 문자열을 변환할 것이다.
  • 이 열을 업데이트 하고 싶으면 반드시 이 형식에 따라 데이터를 삽입해야 한다.
  • 만약 datetime의 내장함수를 이용하면서 '08-Mar-1988'과 같이 데이터를 입력한다면 에러가 나게 된다.

MySQL 자료형에서 공부했었던 날짜형식의 구성요소와 시간 자료형을 다시 살펴볼 수 있다.

문자열을 날짜로 변환

만약 서버가 datetime 값이라고 판단할 수 없거나 기본 형식이 아닌 형식을 사용해서 datetime을 표시하려는 경우, 서버는 문자열을 datetime으로 변환해야 한다.

cast() 함수를 써서 변환해보자.

mysql> SELECT CAST('2021/11/18 21:15:23' AS DATETIME);

+-----------------------------------------+
| CAST('2021/11/18 21:15:23' AS DATETIME) |
+-----------------------------------------+
| 2021-11-18 21:15:23                     |
+-----------------------------------------+
1 row in set (0.00 sec)

날짜 생성 함수

만약 문자열이 cast() 함수를 사용하기에 적절한 형식이 아닐 경우, str_to_date() 함수를 사용할 수 있다. 말 그대로 문자(string)열을 날짜형식(date)으로 바꿔주는 함수다.
형식 문자열의 내용에 따라 datetime, date 또는 time값을 반환한다.

  • 연,월,일,시,분,초 가 다 포함되어 있을 경우 → datetime값 반환
  • 연,월,일 이 포함되어 있을 경우 → date 반환
  • 시,분,초 가 포함되어 있을 경우 → time 반환

날짜 형식의 구성요소

요소정의
%M월명 (January - December)
%m숫자로 나타낸 월 (01 - 12)
%d숫자로 나타낸 일 (01 - 31)
%j일년 중 몇 번째 날 (001 - 366)
%W요일명 (Sunday - Saturday)
%Y연도, 4자리 숫자
%y연도, 2자리 숫자
%H시간 (00 - 23)
%h시간 (01 - 12)
%i분 (00 - 59)
%s초 (00 - 59)
%f마이크로초 (000000 - 999999)
%p오전 또는 오후

현재의 날짜/시간을 생성하고 싶다면 내장함수를 활용하자.

mysql> SELECT CURRENT_DATE(), CURRENT_TIME(), CURRENT_TIMESTAMP();

+----------------+----------------+---------------------+
| CURRENT_DATE() | CURRENT_TIME() | CURRENT_TIMESTAMP() |
+----------------+----------------+---------------------+
| 2021-11-18     | 21:25:50       | 2021-11-18 21:25:50 |
+----------------+----------------+---------------------+
1 row in set (0.00 sec)

시간 데이터 조작

날짜를 반환하는 시간 함수

어떤 날짜를 기준으로 일정 기간을 더하고 싶을 때 내장 시간 함수를 활용할 수 있다.
예를 들어 현재 날짜에 5일을 더하고 싶다고 하면,

mysql> SELECT DATE_ADD(CURRENT_DATE(), INTERVAL 5 DAY);

+------------------------------------------+
| DATE_ADD(CURRENT_DATE(), INTERVAL 5 DAY) |
+------------------------------------------+
| 2021-11-23                               |
+------------------------------------------+
1 row in set (0.00 sec)

INTERVAL 뒤에 사용할 수 있는 일반적인 기간 자료형

기간명정의
second
minute
hour시간
day일 수
month개월 수
year년 수
minute_second:으로 구분된 분 초
hour_second:으로 구분된 시,분,초
year_month-으로 구분된 년,월

하지만 DATE INTERVAL에는 함정도 있다고 한다...! 기간 중에 MONTH의 경우에는, 일정한 값이 아니라 매달 변화하는 값이기 때문에 주의해야 할 것 같다. (1월은 31일, 2월은 28일...)

문자열을 반환하는 시간 함수

  • dayname() : 특정 날짜의 요일을 반환
  • extract() : date의 구성요소 중 일부를 추출
    • 예: SELECT EXTRACT(YEAR FROM '2021-11-18 22:19:05');

🙋🏽‍♀️ 추가 : 날짜 관련 함수들

위에 처럼 extract()를 사용하여 일부를 추출할 수도 있지만 날짜 관련 함수들이 있단 사실을 알게되어 추가로 정리해본다. () 안에는 해당 함수가 계산할수있는 datetime의 요소만 들어있으면 된다.

  • dayofweek(date) : 날짜를 한주의 몇번째 요일인지를 나타내는 숫자로 리턴한다.
    • 일요일 = 1 , 월요일 = 2 , ...
    • 예: dayofweek('1988-03-08');
  • weekday(date) : 날짜를 한 주의 몇 번째 요일인지를 나타내는 숫자로 리턴한다.
    • 월요일 = 0 , 화요일 = 1 ...
  • dayofmonth(date) : 그 달의 몇 번째 날인지 알려준다.
  • dayofyear(date) : 그 해의 몇 번째 날인지 알려준다.
  • month(date) : 해당 날짜가 몇 월인지 알려준다.
  • dayname(date) : 해당 날짜의 영어 요일 이름을 리턴한다.
  • monthname(date) : 해당 날짜의 영어 월 이름을 리턴한다.
  • hour(datetime) : 시간을 알려준다.
  • minute(datetime) : 분을 알려준다.
  • period_diff(p1, p2) : p1과 p2 사이의 기간 사이의 개월 수를 구한다.
  • date_add(date,interval expr type) , date_sub(date,interval expr type) : 특정 날짜에 시간을 더하거나 뺀 값을 알려준다.
    • date에는 기준일, expr에는 일수 또는 시간, type에는 월,일,시간,분,초 등 시간형식을 넣어주면 된다.
    • 예1 : select date_sub("1998-01-02", interval 31 day); → 1997-12-02
    • 예2 : select date_add("1998-01-01 00:00:00",interval "-1 10" day_hour); → 1997-12-30 14:00:00

참고글 : https://jang8584.tistory.com/7

숫자를 반환하는 시간 함수

  • datediff() : 두 개의 date 사이의 기간을 계산하고 싶을 때 사용

예를 들어, 방학기간을 계산하고 싶다고 하자. (방학일: 6/21, 개학일: 9/3)

mysql> SELECT DATEDIFF ('2021-09-03', '2021-06-21');

+---------------------------------------+
| DATEDIFF ('2021-09-03', '2021-06-21') |
+---------------------------------------+
|                                    74 |
+---------------------------------------+
1 row in set (0.00 sec)

🙋🏽‍♀️ 추가 : 날짜를 원하는 형식으로 출력하기

DATE_FORMAT(날짜, 형식)을 이용해 내가 지정한 형식으로 날짜를 출력할 수 있다.

--예1
mysql> SELECT DATE_FORMAT(NOW(), '%Y-%m-%d');
+--------------------------------+
| DATE_FORMAT(NOW(), '%Y-%m-%d') |
+--------------------------------+
| 2021-11-25                     |
+--------------------------------+

--예2
mysql> SELECT DATE_FORMAT(NOW(), '%Y %M %d');
+--------------------------------+
| DATE_FORMAT(NOW(), '%Y %M %d') |
+--------------------------------+
| 2021 November 25               |
+--------------------------------+

--예3
mysql> SELECT DATE_FORMAT(NOW(), '%Y.%m.%d.%r');
+-----------------------------------+
| DATE_FORMAT(NOW(), '%Y.%m.%d.%r') |
+-----------------------------------+
| 2021.11.25.02:00:52 PM            |
+-----------------------------------+

--예4
mysql> SELECT DATE_FORMAT(NOW(), '%Y년%m월%d일 %H시%i분%S초');
+-------------------------------------------------------+
| DATE_FORMAT(NOW(), '%Y년%m월%d일 %H시%i분%S초')          |
+-------------------------------------------------------+
| 20211125140157|
+-------------------------------------------------------+

변환 함수

cast() 함수를 사용하여 문자열을 다른 자료형으로 변환할 수 있다. 이를 위해서는 값(또는 표현식), AS, 변환할 값의 자료형을 제공하면 된다.
문자열을 정수로 변환해보자.

SELECT CAST ('123456' AS SIGNED INTEGER);

이때, 문자열에 정수 숫자 자료형이 아닌 문자가 포함되어 있다면 경고가 나온다.

SELECT CAST('999ABC111' AS UNSIGNED INTEGER);

+---------------------------------------+
| CAST('999ABC111' AS UNSIGNED INTEGER) |
+---------------------------------------+
|                                   999 |
+---------------------------------------+
1 row in set, 1 warning (0.00 sec)

→ ABC는 정수 숫자 자료형이 아니기 때문에 앞의 숫자 3개만 변환되고 나머지 문자열은 버려지게 된다. 서버는 모든 문자열이 변환되지 않았음을 알리는 경고를 날린다.

문자열을 date, time, datetime 자료형으로 변환할 때 주의

  • cast() 함수를 사용하려면 기본 형식을 사용해야 한다. (예: YYYY-MM-DD HH:MI:SS)
  • 만약 날짜 문자열이 기본 형식이 아닐 경우에는 str_to_date() 함수를 사용한다.

좋은 웹페이지 즐겨찾기