이 문서는 2세대 인스턴스인 MySQL용 Cloud SQL 버전 5.7로의 Oracle® 11g/12c 데이터베이스 마이그레이션 계획 및 수행과 관련된 주요 정보 및 안내를 제공하는 시리즈의 일부입니다. 이 시리즈는 다음 문서로 구성되어 있습니다.
- Oracle 사용자를 MySQL용 Cloud SQL로 마이그레이션: 용어 및 기능
- Oracle 사용자를 MySQL용 Cloud SQL로 마이그레이션: 데이터 유형, 사용자, 테이블
- Oracle 사용자를 MySQL용 Cloud SQL로 마이그레이션: 쿼리, 저장 프로시저, 함수, 트리거(이 문서)
- Oracle 사용자를 MySQL용 Cloud SQL로 마이그레이션: 보안, 작업, 모니터링, 로깅
쿼리
Oracle 및 MySQL용 Cloud SQL에서는 ANSI SQL 표준이 지원됩니다. 스칼라 함수 또는 다른 Oracle 확장 기능을 지정하지 않고 기본 구문 요소만 사용해서 SQL 문을 마이그레이션하는 것은 일반적으로 매우 간단합니다. 다음 섹션에서는 일반적인 Oracle 쿼리 요소와 MySQL용 Cloud SQL 해당 요소에 대해 설명합니다.
기본 SELECT 및 FROM 구문
Oracle 기능 이름 또는 구문 이름 | Oracle 개요 또는 구현 | MySQL 지원 | MySQL 해당 구현 또는 대체 솔루션 |
---|---|---|---|
데이터 검색을 위한 SQL 기본 구문 | SELECT FROM WHERE GROUP BY HAVING ORDER BY |
예 | SELECT FROM WHERE GROUP BY HAVING ORDER BY |
출력 인쇄를 위한 SELECT |
SELECT 1 FROM DUAL |
예 | SELECT 1 OR SELECT 1 FROM DUAL |
열 별칭 | SELECT COL1 AS C1 |
예 | SELECT COL1 AS C1 OR SELECT COL1 C1 |
테이블 이름 대소문자 구분 |
대소문자 구분 없음 (예: orders 또는 ORDERS 모두 테이블 이름으로 사용 가능). |
아니요 | 정의된 테이블 이름에 따라 대소문자 구분(예: orders 또는 ORDERS 만 테이블 이름으로 사용 가능) |
자세한 내용은 MySQL SELECT
구문을 참조하세요.
- 인라인 뷰
- 인라인 뷰(파생된 테이블이라고도 함)는
FROM
절에 있는SELECT
문이며, 서브 쿼리로 사용됩니다. - 인라인 뷰는 복합 계산을 없애거나 조인 연산을 제거하고, 여러 개별 쿼리를 간소화된 단일 쿼리로 압축하여 복잡한 쿼리를 간단하게 만드는 데 도움이 될 수 있습니다.
- 변환 참고: Oracle 인라인 뷰에는 별칭을 사용할 필요가 없지만 MySQL에서는 각 인라인 뷰에 특정 별칭이 필요합니다.
- 인라인 뷰(파생된 테이블이라고도 함)는
다음 표에서는 Oracle에서 MySQL로의 인라인 뷰 변환 예시를 보여줍니다.
Oracle 11g/12c |
---|
SQL> SELECT FIRST_NAME, DEPARTMENT_ID, SALARY, DATE_COL FROM EMPLOYEES, (SELECT SYSDATE AS DATE_COL FROM DUAL); 출력은 다음과 비슷합니다. FIRST_NAME DEPARTMENT_ID SALARY DATE_COL -------------------- ------------- ---------- --------- Steven 90 24000 30-JUL-19 Neena 90 17000 30-JUL-19 Lex 90 17000 30-JUL-19 |
MySQL용 Cloud SQL 5.7 |
인라인 뷰에 별칭 없음:mysql> SELECT FIRST_NAME, DEPARTMENT_ID, SALARY, DATE_COL FROM EMPLOYEES, (SELECT SYSDATE() AS DATE_COL FROM DUAL); 인라인 뷰에 별칭 추가: mysql> SELECT FIRST_NAME, DEPARTMENT_ID, SALARY, DATE_COL FROM EMPLOYEES, (SELECT SYSDATE() AS DATE_COL FROM DUAL) AS A1; 출력은 다음과 비슷합니다. +-------------+---------------+----------+---------------------+ | FIRST_NAME | DEPARTMENT_ID | SALARY | DATE_COL | +-------------+---------------+----------+---------------------+ | Steven | 90 | 23996.00 | 2019-07-30 09:28:00 | | Neena | 90 | 22627.00 | 2019-07-30 09:28:00 | | Lex | 90 | 22627.00 | 2019-07-30 09:28:00 | |
JOIN 문
Oracle JOIN
문은 FULL JOIN
절을 제외하고 MySQL JOIN
문에서 지원됩니다. 또한 MySQL JOIN
문은 USING
절, WHERE
절(ON
절 대신), JOIN
문에서 SUBQUERY
사용과 같은 대체 구문 사용을 지원합니다.
다음 표에서는 JOIN 변환 예시를 보여줍니다.
Oracle JOIN 유형 | MySQL에서 지원 | MySQL JOIN 구문 |
---|---|---|
INNER JOIN |
예 | SELECT E.FIRST_NAME, D.DEPARTMENT_NAME FROM EMPLOYEES E JOIN DEPARTMENTS D ON E.DEPARTMENT_ID = D.DEPARTMENT_ID; |
CROSS JOIN |
예 | SELECT E.FIRST_NAME, D.DEPARTMENT_NAME FROM EMPLOYEES E CROSS JOIN DEPARTMENTS D |
FULL JOIN |
아니요 | 문제 해결을 위해서는 LEFT 및 RIGHT JOIN 문에 UNION 을 사용하는 방법을 고려하세요. |
LEFT JOIN [ OUTER ] |
예 | SELECT E.FIRST_NAME, D.DEPARTMENT_NAME FROM EMPLOYEES E LEFT JOIN DEPARTMENTS D ON E.DEPARTMENT_ID = D.DEPARTMENT_ID; |
RIGHT JOIN [ OUTER ] |
예 | SELECT E.FIRST_NAME, D.DEPARTMENT_NAME FROM EMPLOYEES E RIGHT JOIN DEPARTMENTS D ON E.DEPARTMENT_ID = D.DEPARTMENT_ID; |
SUBQUERY |
예 | SELECT E.FIRST_NAME, D.DEPARTMENT_NAME FROM EMPLOYEES E JOIN (SELECT * FROM DEPARTMENTS)D ON E.DEPARTMENT_ID = D.DEPARTMENT_ID; |
UNION, UNION ALL, INTERSECT, MINUS
MySQL은 UNION
및 UNION ALL
함수를 제외하고 Oracle INTERSECT
및 MINUS
함수를 지원하지 않습니다.
UNION
: 2개 이상의SELECT
문의 결과 집합을 연결하고 중복 레코드를 없앱니다.UNION ALL
: 2개 이상의SELECT
문의 결과 집합을 연결하고 중복 레코드를 없애지 않습니다.INTERSECT
: 한 레코드가 두 데이터 집합 모두에 존재할 경우에만 2개 이상의SELECT
문의 교집합을 반환합니다.MINUS
: 2개 이상의SELECT
문을 비교해서 첫 번째 쿼리의 결과 행 중에서 다른 문으로 반환되지 않은 고유 행만 반환합니다.
변환 메모
Oracle INTERSECT
및 MINUS
함수에서 MySQL로 변환할 때 JOIN
문과 IN
및 EXISTS
를 대체 솔루션으로 사용합니다.
예시
Oracle 함수 | Oracle 구현 | MySQL 지원 | MySQL 해당 구현 또는 대체 솔루션 |
---|---|---|---|
UNION |
SELECT COL1 FROM TBL1 UNION SELECT COL1 FROM TBL2 |
예 | SELECT COL1 FROM TBL1 UNION SELECT COL1 FROM TBL2 |
UNION ALL |
SELECT COL1 FROM TBL1 UNION ALL SELECT COL1 FROM TBL2 |
예 | SELECT COL1 FROM TBL1 UNION ALL SELECT COL1 FROM TBL2 |
INTERSECT |
SELECT COL1 FROM TBL1 INTERSECT SELECT COL1 FROM TBL2 |
아니요 | SELECT COL1 FROM TBL1 WHERE COL1 IN (SELECT COL1 FROM TBL2) |
MINUS |
SELECT COL1 FROM TBL1 MINUS SELECT COL1 FROM TBL2 |
아니요 | SELECT A.COL1 FROM TBL1 A LEFT JOIN TBL2 B ON USING(COL1) WHERE B.COL1 IS NULL |
스칼라(단일 행) 및 그룹 함수
MySQL은 광범위한 스칼라(단일 행) 및 집계 함수 목록을 제공합니다. 일부 MySQL 함수는 Oracle 해당 함수와 비슷합니다. 여기에는 이름과 기능이 같은 경우도 있고 이름은 다르지만 기능이 비슷한 경우도 있습니다. MySQL 함수 이름이 Oracle 해당 함수와 같아도, 기능이 다를 수 있습니다.
다음 표에서는 Oracle 및 MySQL 함수의 이름과 기능이 같은 경우('예'로 표시됨)와 변환이 권장되는 경우('예'를 제외한 모든 경우)를 보여줍니다.
문자 함수
Oracle 함수 | Oracle 함수 사양 또는 구현 | MySQL 상응 | MySQL 해당 함수 | MySQL 함수 사양 또는 구현 |
---|---|---|---|---|
CONCAT(str1,str2) |
str1와 연결된 str1을 반환합니다.CONCAT('A', 1) = A1 |
예 | CONCAT |
Oracle과 동일:CONCAT('A', 1) = A1 |
LOWER/UPPER |
모든 문자를 소문자 또는 대문자로 바꿔서 문자를 반환합니다.LOWER('SQL') = sql |
예 | LOWER/UPPER |
Oracle과 동일:LOWER('SQL') = sql |
LPAD/RPAD(expr1,n,expr2) |
n 문자 길이가 되도록 왼쪽 또는 오른쪽에 expr2의 문자 시퀀스가 채워진 상태로 expr1을 반환합니다.LPAD('A',3,'*') = **A |
예 | LPAD/RPAD |
Oracle과 동일:LPAD('A',3,'*') = **A |
SUBSTR(char,p,n) |
char에서 문자 위치 p부터 시작하여 n자 만큼의 하위 문자열 길이에 해당하는 부분을 반환합니다.SUBSTR('MySQL', 3, 3) = SQL |
예 | SUBSTR(char,p,n) |
Oracle과 동일:SUBSTR('MySQL', 3, 3) = SQL |
INSTR(index,str) |
str 문자열의 위치(색인)를 반환합니다.INSTR('MySQL', 'y') = 2 |
예 | INSTR |
Oracle과 동일:INSTR('MySQL', 'y') = 2 |
REPLACE(char,str1,str2) |
검색어로 발견된 모든 문자를 대체 문자열로 바꿔서 반환합니다. REPLACE('ORADB', 'ORA', 'MySQL') |
예 | REPLACE(char,str1,str2) |
Oracle과 동일:REPLACE('ORADB', 'ORA', 'MySQL') |
TRIM(str) |
문자열에서 선행 또는 후행 문자(또는 둘 다)를 자릅니다.TRIM(both '-' FROM '-MySQL-') = MySQL |
예 | TRIM(str) |
Oracle과 동일:TRIM(both '-' FROM '-MySQL-') = MySQL |
LTRIM/RTRIM(str) |
문자열의 왼쪽 또는 오른쪽에서 검색에 표시된 모든 문자를 제거합니다.LTRIM(' MySQL', ' ') = MySQL |
일부만 | LTRIM/RTRIM(str) |
매개변수 대체 항목을 제외한 Oracle R/LTRIM 함수(공백 또는 문자열) MySQL R/LTRIM 은 공백만 없애고 입력 문자열을 수락합니다.LTRIM(' MySQL') = MySQL |
ASCII(char) |
데이터베이스 문자 집합에서 char의 첫 번째 문자의 십진수 표현을 반환합니다. ASCII('A') = 65 |
예 | ASCII(char) |
Oracle과 동일:ASCII('A') = 65 |
CHR(char) |
0~225 사이의 숫자 값인 ASCII 코드 값을 해당 문자로 반환합니다.CHR(65) = A |
부분적으로 다른 함수 이름 | CHAR(char) |
MySQL에서는 동일 기능으로 CHAR 함수가 사용됩니다. 따라서 함수 이름을 수정해야 합니다.CHAR(65) = A |
LENGTH(str) |
제공된 문자열의 길이를 반환합니다.LENGTH ('MySQL') = 5 |
예 | LENGTH(str) |
Oracle과 동일:LENGTH('MySQL') = 5 |
REGEXP_REPLACE(str1,expr,str2) |
정규 표현식 패턴의 문자열을 검색합니다.REGEXP_REPLACE('John', '[hn].', '1') = Jo1 |
아니요 | 해당 사항 없음 | MySQL 버전 8부터만 지원됩니다. 문제 해결을 위해서는 가능한 경우 REPLACE 함수를 사용하고, 그렇지 않으면 애플리케이션 레이어로 변환합니다. |
REGEXP_SUBSTR(str,expr) |
정규 표현식 패턴에 대해 문자열을 검색하여 SUBSTR 함수의 기능을 확장합니다.REGEXP_SUBSTR('https://console.cloud.google.com/sql/instances','https://([[:alnum:]]+\.?){3,4}/?') = https://console.cloud.google.com/ |
아니요 | 해당 사항 없음 | MySQL 버전 8부터만 지원됩니다. 문제 해결을 위해서는 가능한 경우 SUBSTR 함수를 사용하고, 그렇지 않으면 애플리케이션 레이어로 기능을 변환합니다. |
REGEXP_COUNT(str,expr) |
패턴이 소스 문자열에 있는 횟수를 반환합니다. | 아니요 | 해당 사항 없음 | 대체 솔루션을 위해서는 애플리케이션 레이어로 기능을 변환합니다. |
REGEXP_INSTR(index,expr) |
정규 표현식 패턴에 대해 문자열 위치(색인)를 검색합니다. | 아니요 | 해당 사항 없음 | MySQL 버전 8부터만 지원됩니다. |
REVERSE(str) |
역순으로 표시된 문자열을 반환합니다.REVERSE('MySQL') = LQSyM |
예 | REVERSE |
Oracle과 동일:REVERSE('MySQL') = LQSyM |
숫자 함수
Oracle 함수 | Oracle 함수 사양 또는 구현 | MySQL 상응 | MySQL 해당 함수 | MySQL 함수 사양 또는 구현 |
---|---|---|---|---|
ABS(n) |
n의 절댓값입니다. ABS(-4.6) = 4.6 |
예 | ABS |
Oracle과 동일:ABS(-4.6) = 4.6 |
CEIL(n) |
n보다 크거나 같은 가장 작은 정수를 반환합니다.CEIL(21.4) = 22 |
예 | CEIL |
Oracle과 동일:CEIL(21.4) = 22 |
FLOOR(n) |
n보다 작거나 같은 가장 큰 정수를 반환합니다. FLOOR(-23.7) = -24 |
예 | FLOOR |
Oracle과 동일:FLOOR(-23.7) = -24 |
MOD(m,n) |
m을 n으로 나눈 나머지를 반환합니다.MOD(10, 3) = 1 |
예 | MOD(m,n) |
Oracle과 동일:MOD(10,3) = 1 |
ROUND(m,n) |
m을 소수점 오른쪽 정수 자릿수 n으로 반올림하여 반환합니다.ROUND(1.39,1) = 1.4 |
예 | ROUND |
Oracle과 동일:ROUND(1.39,1) = 1.4 |
TRUNC(n1, n2) |
n1을 n2 소수점 자릿수로 잘라서 반환합니다.TRUNC(99.999) = 99 TRUNC(99.999,0) = 99 |
부분적으로 다른 함수 이름 | TRUNCATE(n1, n2) |
MySQL TRUNCATE 함수는 입력 숫자 및 정수 숫자를 사용해서 소수점 자릿수 오른쪽의 정확도를 지정해야 합니다.TRUNCATE(99.999,0) = 99 |
날짜 및 시간 함수
Oracle 함수 | Oracle 함수 사양 또는 구현 | MySQL 상응 | MySQL 해당 함수 | MySQL 함수 사양 또는 구현 |
---|---|---|---|---|
SYSDATE |
데이터베이스 서버가 있는 운영체제에 설정된 현재 날짜 및 시간을 반환합니다.SELECT SYSDATE FROM DUAL = 31-JUL-2019 |
일부만 | SYSDATE() |
MySQL SYSDATE() 는 괄호를 포함해야 하며, Oracle SYSDATE 함수와 다른 날짜/시간 형식을 반환합니다.SELECT SYSDATE() FROM DUAL; = 2019-01-31 10:01:01.0 날짜/시간 형식은 세션 수준에서 변경할 수 있습니다. |
SYSTIMESTAMP |
소수점 이하 초와 시간대를 포함하여 시스템 날짜를 반환합니다.SELECT SYSTIMESTAMP FROM DUAL = 01-JAN-19 07.37.11.622187000 AM +00:00 |
부분적으로 다른 함수 이름 | CURRENT_TIMESTAMP |
MySQL은 Oracle과 다른 날짜/시간 형식을 반환합니다. 원래 날짜/시간 형식과 같게 하려면 날짜 형식을 조정하거나 다른 날짜 함수를 사용해야 합니다.SELECT CURRENT_TIMESTAMP FROM DUAL = 2019-01-31 06:55:07 |
LOCAL_TIMESTAMP |
세션 시간대에서 현재 날짜 및 시간을 TIMESTAMP 데이터 형식의 값으로 반환합니다.SELECT LOCAL_TIMESTAMP FROM DUAL = 01-JAN-19 10.01.10.123456 PM |
부분적으로 날짜/시간 형식이 다릅니다. | LOCAL_TIMESTAMP |
MySQL은 Oracle과 다른 날짜/시간 형식을 반환합니다. 원래 날짜/시간 형식과 같게 하려면 날짜/시간 형식을 조정하거나 다른 날짜 함수를 사용해야 합니다.SELECT LOCAL_TIMESTAMP FROM DUAL = 2019-01-01 10:01:01.0 |
CURRENT_DATE |
세션 시간대에서 현재 날짜를 반환합니다.SELECT CURRENT_DATE FROM DUAL = 31-JAN-19 |
부분적으로 날짜/시간 형식이 다릅니다. | CURRENT_DATE |
MySQL은 Oracle과 다른 날짜/시간 형식을 반환합니다. 원래 날짜/시간 형식과 같게 하려면 날짜/시간 형식을 조정하거나 다른 날짜 함수를 사용해야 합니다.SELECT CURRENT_DATE FROM DUAL = 2019-01-31 |
CURRENT_TIMESTAMP |
세션 시간대에서 현재 날짜 및 시간을 반환합니다.SELECT CURRENT_TIMESTAMP FROM DUAL = 31-JAN-19 06.54.35.543146 AM +00:00 |
부분적으로 날짜/시간 형식이 다릅니다. | CURRENT_TIMESTAMP |
MySQL은 Oracle과 다른 날짜/시간 형식을 반환합니다. 원래 날짜/시간 형식과 같게 하려면 날짜/시간 형식을 조정하거나 다른 날짜 함수를 사용해야 합니다.SELECT CURRENT_TIMESTAMP FROM DUAL = 2019-01-31 06:55:07 |
ADD_MONTHS |
날짜와 정수 월을 반환합니다.ADD_MONTHS(SYSDATE, 1) = 31-JAN-19 |
부분적으로 다른 함수 이름 | ADDDATE |
동일 기능을 제공하기 위해 MySQL에서는 ADDDATE 함수가 사용됩니다.ADDDATE(SYSDATE(), 1) = 2019-08-01 06:42:49.0 기본적으로 MySQL은 Oracle과 다른 날짜/시간 및 범위/형식을 반환합니다. 원래 날짜/시간 형식과 같게 하려면 날짜/시간 형식을 조정하거나 다른 날짜 함수를 사용해야 합니다. |
EXTRACT (날짜 부분) |
날짜/시간 또는 간격 표현식에서 지정된 날짜/시간 필드의 값을 반환합니다.EXTRACT(YEAR FROM DATE '2019-01-31') = 2019 |
예 | EXTRACT (날짜 부분) |
Oracle과 동일:EXTRACT(YEAR FROM DATE '2019-01-31') = 2019 |
LAST_DAY |
해당 월의 마지막 일자의 날짜를 반환합니다.LAST_DAY('01-JAN-2019') = 31-JAN-19 |
부분적으로 날짜/시간 형식이 다릅니다. | LAST_DAY |
MySQL은 Oracle과 다른 날짜/시간 형식을 반환합니다. 원래 날짜/시간 형식과 같게 하려면 날짜/시간 형식을 조정하거나 다른 날짜 함수를 사용해야 합니다.LAST_DAY('2019-01-01') = 2019-01-31 |
MONTH_BETWEEN |
date1과 date2 날짜 사이의 개월 수를 반환합니다.MONTHS_BETWEEN( SYSDATE, SYSDATE-60) = 1.96 |
부분적으로 다른 함수 이름 | PERIOD_DIFF(date1,date2) |
MySQL PERIOD_DIFF 함수는 두 기간(YYMM 또는 YYYYMM 형식) 사이의 개월 수 차이를 정수 숫자로 반환합니다.PERIOD_DIFF( '201903', '201901') = 2 Oracle MONTH_BETWEEN 함수와 동일한 값을 얻기 위해서는 보다 구체적인 변환이 필요합니다. |
TO_CHAR (날짜/시간) |
날짜 형식으로 지정된 형식에 따라 날짜/시간 또는 타임스탬프 데이터 유형을 VARCHAR2 데이터 유형의 값으로 변환합니다.TO_CHAR( SYSDATE,'DD-MM-YYYY HH24:MI:SS') = 01-01-2019 10:01:01 |
부분적으로 다른 함수 이름 | DATE_FORMAT |
MySQL DATE_FORMAT 함수는 날짜 형식 정의에 지정된 대로 날짜 형식을 지정합니다.DATE_FORMAT( SYSDATE(),'%d-%m-%Y %H:%i:%s') = 01-01-2019 10:01:01 |
인코딩 및 디코딩 기능
Oracle 함수 | Oracle 함수 사양 또는 구현 | MySQL 상응 | MySQL 해당 함수 | MySQL 함수 사양 또는 구현 |
---|---|---|---|---|
DECODE |
IF-THEN-ELSE 문의 기능을 사용하여 표현식을 각 검색 값과 하나씩 비교합니다. |
아니요 | CASE |
MySQL CASE 문을 사용하여 비슷한 기능을 제공합니다. |
DUMP |
데이터 유형 코드, 바이트 길이, 제공된 표현식의 내부 표현이 포함된 VARCHAR2 값을 반환합니다. |
아니요 | 해당 사항 없음 | 지원되지 않음 |
ORA_HASH |
제공된 표현식의 해시 값을 계산합니다. | 아니요 | MD5/SHA |
128비트 체크섬에는 MySQL MD5 를 사용하고 160비트 체크섬에는 SHA 함수를 사용하여 해시 값을 생성합니다. |
변환 함수
Oracle 함수 | Oracle 함수 사양 또는 구현 | MySQL 상응 | MySQL 해당 함수 | MySQL 함수 사양 또는 구현 |
---|---|---|---|---|
CAST |
기본 제공되는 한 가지 데이터 유형 또는 컬렉션 유형의 값을 다른 기본 제공되는 데이터 유형 또는 컬렉션 유형의 값으로 변환합니다. CAST('1' as int) + 1 = 2 |
일부만 | CAST |
MySQL CAST 함수는 Oracle 기능과 비슷하지만 경우에 따라 명시적 또는 암시적 변환이 필요한지 여부에 따라 조정이 필요합니다.CAST('1' AS SIGNED) + 1 = 2 |
CONVERT |
한 가지 문자 집합에서 다른 문자 집합으로 문자 문자열을 변환합니다. CONVERT('Ä Ê Í Õ Ø A B C D E ', 'US7ASCII', 'WE8ISO8859P1') = ?? ?? ?? A B C |
일부만 | CONVERT |
Oracle과 정확히 동일한 결과를 반환하기 위해서는 MySQL CONVERT 함수에서 구문 및 매개변수를 일부 조정해야 합니다.CONVERT('Ä Ê Í A B C ' USING utf8) = Ä Ê Í A B C |
TO_CHAR (문자열/숫자) |
이 함수는 숫자 또는 날짜를 문자열로 변환합니다. TO_CHAR(22.73,'$99.9') = $22.7 |
아니요 | FORMAT |
MySQL FORMAT 함수는 숫자에서 '#,###.##' 형식을 수행하고, 특정 소수점 자릿수로 반올림한 후 결과를 문자열로 반환합니다. 이 함수는 Oracle과 기능이 다릅니다.CONCAT('$', FORMAT(22.73, 1)) = $22.7 |
TO_DATE |
Oracle TO_DATE 함수는 소스 특정 날짜/숫자 형식에 따라 문자열을 날짜로 변환합니다.TO_DATE( '2019/01/01', 'yyyy-mm-dd') = 01-JAN-2019 |
부분적으로 함수 이름 및 날짜/시간 형식이 다릅니다. | STR_TO_DATE |
MySQL STR_TO_DATE 함수는 문자열을 입력해서 날짜/시간 형식으로 지정된 날짜를 반환합니다.STR_TO_DATE( '2019/01/01', '%Y/%m/%d') = 2019-01-01 |
TO_NUMBER |
표현식을 NUMBER 데이터 유형의 값으로 변환합니다.TO_NUMBER('01234') = 1234 |
아니요 | CAST |
대신 MySQL CAST 함수를 사용하여 Oracle TO_NUMBER 와 동일한 결과를 반환합니다.CAST('01234' as SIGNED) = 1234 |
조건부 SELECT 함수
Oracle 함수 | Oracle 함수 사양 또는 구현 | MySQL 상응 | MySQL 해당 함수 | MySQL 함수 사양 또는 구현 |
---|---|---|---|---|
CASE |
CASE 문은 일련의 조건을 선택하여 다음 구문으로 해당 문을 실행합니다. CASE WHEN condition THEN result [WHEN ...] [ELSE result] END |
예 | CASE |
CASE 함수 외에도 MySQL에서는 SELECT 문 내에서 IF/ELSE 조건 처리 사용이 지원됩니다.CASE WHEN condition THEN result [WHEN ...] [ELSE result] END |
Null 함수
Oracle 함수 | Oracle 함수 사양 또는 구현 | MySQL 상응 | MySQL 해당 함수 | MySQL 함수 사양 또는 구현 |
---|---|---|---|---|
COALESCE |
표현식 목록에서 null 아닌 첫 번째 표현식을 반환합니다.COALESCE( null, '1', 'a') = a |
예 | COALESCE |
Oracle과 동일:COALESCE( null, '1', 'a') = 1 |
NULLIF |
expr1과 expr2m을 비교합니다. 두 표현식이 동일하면 함수가 null을 반환합니다. 서로 다르면 함수가 expr1을 반환합니다. NULLIF('1', '2') = a |
예 | NULLIF |
Oracle과 동일:NULLIF('1', '2') = a |
NVL |
null(공백으로 반환됨)을 쿼리 결과의 문자열로 바꿉니다.NVL(null, 'a') = a |
아니요 | IFNULL |
MySQL 해당 함수는 null 값을 제공된 문자열로 바꾸는 IFNULL 함수입니다.IFNULL(null, 'a') = a |
NVL2 |
지정된 표현식이 null인지 여부에 따라 쿼리로 반환되는 값을 결정합니다. |
아니요 | CASE |
CASE 문은 일련의 조건을 선택하여 해당 문을 실행합니다. CASE WHEN condition THEN result [WHEN ...] [ELSE result] END |
환경 및 식별자 함수
Oracle 함수 | Oracle 함수 사양 또는 구현 | MySQL 상응 | MySQL 해당 함수 | MySQL 함수 사양 또는 구현 |
---|---|---|---|---|
SYS_GUID |
최대 16바이트로 구성된 전역 고유 식별자(RAW 값)를 생성하고 반환합니다.SELECT SYS_GUID() FROM DUAL = 8EFA4A31468B4C6DE05011AC0200009E |
아니요 | REPLACE 및 UUID |
문제 해결을 위해서는 MySQL REPLACE 및 UUID 함수를 사용하여 Oracle SYS_GUID 함수를 시뮬레이션합니다.REPLACE( UUID(), '-', '') |
UID |
세션 사용자(로그온된 사용자)를 고유하게 식별하는 정수를 반환합니다. SELECT UID FROM DUAL = 43 |
아니요 | 해당 사항 없음 | 해당 사항 없음 |
USER |
현재 세션 사용자의 이름을 반환합니다.SELECT USER FROM DUAL = UserName |
일부만 | USER + INSTR + SUBSTR |
MySQL USER 함수는 연결 서버(root@IP )와 함께 사용자 이름을 반환합니다. 사용자 이름만 반환하려면 추가 지원 함수를 사용하세요.SELECT SUBSTR(USER(), 1, INSTR(USER(), '@') -1) FROM DUAL = root |
USERENV |
현재 매개변수 구성을 사용하여 현재 사용자 세션에 대한 정보를 반환합니다.SELECT USERENV('LANGUAGE') FROM DUAL = ENGLISH_AMERICA.AL32UTF8 |
아니요 | SHOW SESSION VARIABLES |
MySQL SHOW SESSION VARIABLES 문을 사용하여 현재 세션에 대한 설정을 확인합니다.SHOW SESSION VARIABLES LIKE '%collation%'; = utf8_general_ci |
ROWID |
Oracle 서버는 테이블의 행을 식별하기 위해 각 테이블의 각 행에 고유한 ROWID 를 할당합니다. ROWID 는 데이터 객체 번호, 행의 데이터 블록, 행 위치, 데이터 파일이 포함된 행의 주소입니다. |
아니요 | 해당 사항 없음 | 가능한 경우 다른 MySQL 함수로 동일한 기능 에뮬레이션을 시도하세요. |
ROWNUM |
Oracle이 테이블 또는 조인된 테이블에서 행을 선택한 순서를 나타내는 숫자를 반환합니다. | 아니요 | 해당 사항 없음 | 가능한 경우 다른 MySQL 함수 또는 세션 변수로 동일한 기능 에뮬레이션을 시도하세요. |
집계(그룹) 함수
Oracle 함수 | Oracle 함수 사양 또는 구현 |
MySQL 상응 |
MySQL 해당 함수 | MySQL 함수 사양 또는 구현 |
---|---|---|---|---|
AVG |
열 또는 표현식의 평균 값을 반환합니다. | 예 | AVG |
Oracle과 동일 |
COUNT |
쿼리로 반환된 행 수를 반환합니다. | 예 | COUNT |
Oracle과 동일 |
COUNT (DISTINCT) |
열 또는 표현식에 있는 고유 값 수를 반환합니다. | 예 | COUNT (DISTINCT) |
Oracle과 동일 |
MAX |
열 또는 표현식의 최댓값을 반환합니다. | 예 | MAX |
Oracle과 동일 |
MIN |
열 또는 표현식의 최솟값을 반환합니다. | 예 | MIN |
Oracle과 동일 |
SUM |
열 또는 표현식의 값의 합계를 반환합니다. | 예 | SUM |
Oracle과 동일 |
LISTAGG |
측정 열의 값을 연결하여 ORDER BY 절에 지정된 단일 행에 따라 각 그룹 내의 데이터를 표시합니다.SELECT LISTAGG( DEPARTMENT_NAME, ', ') WITHIN GROUP (ORDER BY DEPARTMENT_NAME) DEPT FROM DEPARTMENTS; |
아니요 | GROUP_CONCAT |
MySQL GROUP_CONCAT 함수를 사용해서 Oracle과 비슷한 결과를 반환합니다. 경우에 따라 구문이 달라질 수 있습니다.SELECT GROUP_CONCAT( DEPARTMENT_NAME ORDER BY DEPARTMENT_NAME SEPARATOR ', ') DEPT FROM DEPARTMENTS; |
Oracle 12c 가져오기
Oracle 함수 | Oracle 함수 사양 또는 구현 |
MySQL 상응 |
MySQL 해당 함수 | MySQL 함수 사양 또는 구현 |
---|---|---|---|---|
FETCH |
다중 행 쿼리의 결과 집합에서 데이터 행을 검색합니다. SELECT * FROM EMPLOYEES FETCH FIRST 10 ROWS ONLY; |
아니요 | LIMIT | MySQL LIMIT 절을 사용하여 특정 레코드 집합만 검색합니다.SELECT * FROM EMPLOYEES LIMIT 10; |
기본 필터링, 연산자, 서브 쿼리
변환 중 기본 필터링, 연산자 함수, 하위 쿼리는 최소한의 추가 작업으로 비교적 직관적으로 수행됩니다.
변환 메모
Oracle과 MySQL 형식이 서로 다른 기본 결과를 반환하기 때문에 날짜 형식을 조사하고 해결합니다.
- Oracle
SYSDATE
함수는 기본적으로01-AUG-19
를 반환합니다. - MySQL
SYSDATE()
함수는 기본적으로2019-08-01 12:04:05
를 반환합니다. - 날짜 및 시간 형식은 MySQL
[DATE_FORMAT](https://dev.mysql.com/doc/refman/5.7/en/date-and-time-functions.html#function_date-format)
또는[STR_TO_DATE](https://dev.mysql.com/doc/refman/5.7/en/date-and-time-functions.html#function_str-to-date)
함수를 사용하여 설정할 수 있습니다.
Oracle 함수 또는 하위 쿼리 | MySQL 상응 | MySQL 해당 함수 또는 하위 쿼리 | MySQL 함수 사양 또는 구현 |
---|---|---|---|
EXISTS/NOT EXISTS |
예 | EXISTS/NOT EXISTS |
SELECT * FROM DEPARTMENTS D WHERE EXISTS (SELECT 1 FROM EMPLOYEES E WHERE E.DEPARTMENT_ID = D.DEPARTMENT_ID); |
IN/NOT IN |
예 | IN/NOT IN |
SELECT * FROM DEPARTMENTS D WHERE DEPARTMENT_ID IN (SELECT DEPARTMENT_ID FROM EMPLOYEES E); |
LIKE/NOT LIKE |
예 | LIKE/NOT LIKE |
SELECT * FROM EMPLOYEES WHERE FIRST_NAME LIKE '_e_n%'; |
BETWEEN/NOT BETWEEN |
예 | BETWEEN/NOT BETWEEN |
SELECT * FROM EMPLOYEES WHERE EXTRACT(YEAR FROM HIRE_DATE) NOT BETWEEN 2001 and 2004; |
AND/OR |
예 | AND/OR |
SELECT * FROM EMPLOYEES WHERE DEPARTMENT_ID IN(100, 101) AND (SALARY >= 1000 OR HIRE_DATE <= '2006-02-05'); |
SubQuery |
예 | SubQuery |
MySQL은 JOIN 문 및 WHERE/AND 절의 필터링에 대해 SELECT 수준의 하위 쿼리를 지원합니다.-- SELECT SubQuery SELECT D.DEPARTMENT_NAME, (SELECT AVG(SALARY) AS AVG_SAL FROM EMPLOYEES E WHERE E.DEPARTMENT_ID = D.DEPARTMENT_ID) AVG_SAL FROM DEPARTMENTS D; |
연산자 | 예 | 연산자 | MySQL은 모든 기본 연산자를 지원합니다.> | >= | < | <= | = | <> | != |
분석 함수(또는 윈도우 및 순위 함수)
Oracle 분석 함수는 행 그룹을 기준으로 집계 값을 계산하는 기능을 제공하여 표준 SQL 분석 함수의 기능을 확장합니다. 이러한 함수는 단일 쿼리 표현식의 범위 내에서 논리적으로 파티션을 나눈 결과 집합에 적용될 수 있습니다. 일반적으로 비즈니스 인텔리전스 보고서 및 분석과 함께 사용되며, 보다 복잡하고 비분석적인 SQL 코드를 사용하여 동일한 결과를 얻을 때보다 쿼리 성능이 크게 향상될 수 있습니다.
변환 메모
- MySQL 버전 5.7은 직관적인 SQL 문 변환을 지원하는 분석 함수를 제공하지 않습니다. 하지만 이 기능이 MySQL 버전 8에 부분적으로 추가되어, 마이그레이션 프로세스에 필요한 수동 작업과 같이 분석 함수 변환을 일부 고려할 수 있게 되었습니다.
- 한 가지 선택적인 솔루션은 분석 함수를 사용하지 않도록 코드를 다시 작성해서 보다 전통적인 SQL 코드 솔루션으로 되돌리거나 이 논리를 애플리케이션 레이어로 이동하는 것입니다.
다음 표에서는 Oracle의 일반적인 분석 함수를 보여줍니다.
함수 계열 | 관련 함수 | MySQL 5.7에서 지원 |
---|---|---|
분석 및 순위 | RANK AVERAGE_RANK DENSE_RANK RANK ROW_NUMBER PERCENT_RANK CUME_DIST NTILE FIRST_VALUE LAST_VALUE OVER (PARTITION BY...) |
아니요 |
계층 | CONNECT BY HIER_ANCESTOR HIER_CHILD_COUNT HIER_DEPTH HIER_LEVEL HIER_ORDER HIER_PARENT HIER_TOP |
아니요 |
지연 | LAG LAG_VARIANCE LAG_VARIANCE_PERCENT LEAD LEAD_VARIANCE LEAD_VARIANCE_PERCENT |
아니요 |
공통 테이블 표현식(CTE)
CTE는 여러 용도로 사용하기에 너무 복잡하거나 비효율적일 수 있는 SQL 코드를 재사용하기 위해 순차적 코드의 논리를 구현할 수 있는 방법을 제공합니다. CTE는 이름을 지정하고 WITH
절을 사용하여 SQL 문의 서로 다른 부분에서 여러 번 사용될 수 있습니다.
변환 메모
- MySQL 버전 5.7에서는 CTE가 지원되지 않고 MySQL 버전 8에서 지원됩니다.
- 다른 솔루션을 위해서는 파생된 테이블 또는 하위 쿼리를 사용하거나 CTE 기능이 제거되도록 SQL 문을 다시 작성합니다.
예시
Oracle |
---|
WITH DEPT_COUNT (DEPARTMENT_ID, DEPT_COUNT) AS (SELECT DEPARTMENT_ID, COUNT(*) FROM EMPLOYEES GROUP BY DEPARTMENT_ID) |
MySQL |
SELECT * FROM ( SELECT CONCAT(E.FIRST_NAME, ' ', E.LAST_NAME) AS EMP_NAME, (SELECT COUNT(*) FROM EMPLOYEES D WHERE E.DEPARTMENT_ID = D.DEPARTMENT_ID GROUP BY DEPARTMENT_ID) AS EMP_DEPT_COUNT FROM EMPLOYEES E ORDER BY 2 DESC) TBL WHERE EMP_DEPT_COUNT IS NOT NULL; |
MERGE 문
MERGE
(또는 UPSERT
) 문은 개별적으로 실행되는 단일 DML 문과 달리 하나의 MERGE
작업으로 DML 작업을 조건부로 수행하는 단일 SQL 문을 지정할 수 있는 방법을 제공합니다. 소스 테이블에서 레코드를 선택한 후 논리적 구조를 지정하여 대상 테이블에서 여러 DML 작업을 자동으로 수행합니다. 이 기능은 삽입, 업데이트, 삭제를 여러 번 사용하지 않도록 도와줍니다. MERGE
는 결정적 문입니다. 즉, MERGE
문으로 행이 처리된 다음에는 동일한 MERGE
문을 사용해서 이를 다시 처리할 수 없습니다.
변환 메모
MySQL 버전 5.7에서는 Oracle과 달리 MERGE
기능이 지원되지 않습니다. MERGE
기능을 부분적으로 시뮬레이션하기 위해 MySQL은 REPLACE
및 INSERT… ON DUPLICATE KEY UPDATE
문을 제공합니다.
REPLACE
:INSERT
문과 동일한 방식으로 작동하지만, 테이블의 이전 행에PRIMARY KEY
또는UNIQUE
색인의 새 행과 동일한 값이 포함된 경우, 새 행이 삽입되기 전에 이전 행이 삭제됩니다.INSERT… ON DUPLICATE KEY UPDATE
: 삽입된 행으로 인해PRIMARY KEY
또는UNIQUE
색인에 값이 중복될 경우 중복 키 예외를 없애기 위해 이전 행에 대해UPDATE
가 수행됩니다. 예를 들면 다음과 같습니다.INSERT INTO tbl (a,b,c) VALUES (1,2,3) ON DUPLICATE KEY UPDATE c=c+1; UPDATE tbl SET c=c+1 WHERE a=1;
또 다른 솔루션은 예외 및 중복 처리와 함께 INSERT
, UPDATE
, DELETE
명령어를 사용해서 DML 작업을 관리하도록 MERGE
기능을 저장 프로시져로 변환하는 것입니다.
SQL 문 힌트
Oracle은 사용자가 옵티마이저 동작에 영향을 줄 수 있게 해주는 대규모 SQL 쿼리 힌트 모음과 보다 효율적인 쿼리 실행 계획을 만들기 위한 의사결정 기능을 제공합니다. Oracle은 60개 이상의 데이터베이스 힌트를 지원합니다. MySQL은 제한적인 쿼리 힌트 집합을 제공합니다.
일반적으로 MySQL 버전 5.7은 OPTIMIZER
HINTS
및 INDEX HINTS
라는 두 가지 유형의 쿼리 힌트를 지원합니다.
MySQL 옵티마이저 힌트는 개별 SQL 문 내에서 옵티마이저 동작을 제어할 수 있는 기능을 제공합니다. 예를 들면 다음과 같습니다.
SELECT /*+ NO_RANGE_OPTIMIZATION(tbl PRIMARY, col1_idx) */ col1 FROM tbl;
MySQL MySQL
힌트 이름 | 힌트 개요 | 적용 가능한 범위 |
---|---|---|
BKA, NO_BKA |
일괄 키 액세스 조인 처리에 영향을 줍니다. | 쿼리 블록, 테이블 |
BNL, NO_BNL |
블록 중첩 루프 조인 처리에 영향을 줍니다. | 쿼리 블록, 테이블 |
MAX_EXECUTION_TIME |
문 실행 시간을 제한합니다. | 전역 |
MRR, NO_MRR |
다중 범위 읽기 최적화에 영향을 줍니다. | 테이블, 색인 |
NO_ICP |
색인 조건 푸시다운 최적화에 영향을 줍니다. | 테이블, 색인 |
NO_RANGE_OPTIMIZATION |
범위 최적화에 영향을 줍니다. | 테이블, 색인 |
QB_NAME |
쿼리 블록에 이름을 할당합니다. | 쿼리 블록 |
SEMIJOIN, NO_SEMIJOIN |
세미 조인 전략에 영향을 줍니다. | 쿼리 블록 |
SUBQUERY |
구체화, IN -EXISTS 하위 쿼리 전략에 영향을 줍니다. |
쿼리 블록 |
MySQL 색인 힌트는 쿼리 처리 중 색인 선택 방법에 대한 정보를 옵티마이저에 제공합니다. USE
, FORCE
, IGNORE
키워드는 옵티마이저 색인 사용 프로세스를 제어하기 위해 사용됩니다. 예를 들면 다음과 같습니다.
SELECT * FROM tbl USE INDEX (col1_index, col2_index);
-- OR
SELECT * FROM tbl IGNORE INDEX (col1_index, col2_index);
변환 메모
Oracle 및 MySQL 옵타마이저 사이에는 근본적인 차이가 있고, Oracle 및 MySQL 쿼리 힌트 간에 겹치는 부분이 있더라도 제한적이기 때문에, 지정되지 않은 쿼리 힌트가 포함된 모든 Oracle SQL 문을 대상 MySQL 데이터베이스로 변환하는 것이 좋습니다.
사용 사례에 따라 실행 계획을 사용하고 인스턴스 또는 세션 파라미터를 조정하여 MySQL 도구(예: 실시간 성능 대시보드를 위한 MySQL Workbench) 및 쿼리 조사와 같은 기능을 통해 MySQL 성능조정을 수행하세요.
실행 계획
실행 계획의 기본 목적은 데이터베이스 데이터에 액세스하기 위해 쿼리 옵티마이저에서 선택한 방법으로 내부 조사를 수행하는 것입니다. 쿼리 옵티마이저는 데이터베이스 사용자를 위해 SELECT
, INSERT
, UPDATE
, DELETE
문에 대한 실행 계획을 생성합니다. 관리자의 경우에도 특정 쿼리 및 DML 작업을 보다 효율적으로 확인할 수 있습니다. 이것들은 쿼리 성능 조정을 수행해야 할 때 특히 유용합니다. 예를 들어 색인 성능을 확인하거나 생성이 필요한 색인 중 누락된 것이 있는지 확인할 수 있습니다.
실행 계획은 데이터 볼륨, 데이터 통계, 인스턴스 매개변수(전역 또는 세션 매개변수)의 영향을 받을 수 있습니다.
변환 고려사항
실행 계획은 마이그레이션이 필요한 데이터베이스 객체가 아닙니다. 오히려 동일한 데이터세트에서 동일한 문을 실행하여 Oracle과 MySQL 사이의 성능 차이를 분석하기 위한 도구입니다.
MySQL은 Oracle과 동일한 실행 계획 구문, 기능, 출력을 지원하지 않습니다.
예시
Oracle 실행 계획 |
---|
SQL> EXPLAIN PLAN FOR SELECT * FROM EMPLOYEES WHERE EMPLOYEE_ID = 105; |
MySQL 실행 계획 |
mysql> EXPLAIN SELECT * FROM EMPLOYEES WHERE EMPLOYEE_ID = 105; |
저장 프로시져, 함수, 트리거
PL/SQL은 데이터베이스 내에서 코드 기반 솔루션을 생성, 저장, 적용하기 위해 사용되는 Oracle 확장 절차적 언어입니다. 일반적으로 데이터베이스 저장 프로시져와 함수는 ANSI SQL과 Oracle용 PL/SQL, PostgreSQL용 PL/pgSQL, MySQL용 MySQL 절차적 언어와 같은 SQL 확장 절차적 언어로 구성되는 코드 요소입니다. MySQL은 자체의 고유 확장 절차적 언어에 대해 데이터베이스와 동일한 이름을 사용합니다.
이러한 저장 프로시져 및 함수의 목적은 성능, 호환성, 보안 등 애플리케이션 대신 데이터베이스 내에서 실행하기에 더 적합한 경우에 대한 솔루션을 제공하는 것입니다. 저장 프로시져와 함수 모두 PL/SQL이 사용되지만 저장 프로시져는 주로 DDL/DML 작업을 수행하기 위해 사용되고, 함수는 주로 특정 결과 반환을 위한 계산을 수행하기 위해 사용됩니다.
PL/SQL과 MySQL 절차적 언어
Oracle PL/SQL에서 MySQL로의 코드 마이그레이션 관점에서 MySQL 절차적 구현은 Oracle과 방식이 다릅니다. 따라서 Oracle의 PL/SQL 기능을 MySQL 저장 프로시져 및 함수로 변환하기 위해 코드 마이그레이션이 필요합니다. 또한 Oracle Package 및 Package Body가 MySQL에서 지원되지 않으므로, 코드 변환을 수행할 때 이러한 요소를 단일 MySQL 코드 단위로 변환(또는 파싱)합니다. 또한 MySQL 저장 프로시져 및 함수를 routines이라고도 합니다.
코드 객체 소유자
Oracle에서 저장 프로시져 또는 함수의 소유자는 특정 사용자입니다. MySQL에서는 소유자가 특정 스키마(데이터베이스 사용자에 의해 데이터베이스에 생성됨)입니다.
코드 객체 권한 및 보안
Oracle에서는 저장 프로시져 또는 함수를 만들기 위해 사용자에게 CREATE PROCEDURE
시스템 권한이 있어야 합니다(다른 사용자로 프로시져 또는 함수를 만들려면 데이터베이스 사용자에게 CREATE
ANY PROCEDURE
권한이 있어야 함). 저장 프로시져 또는 함수를 실행하기 위해서는 데이터베이스 사용자에게 EXECUTE
권한이 있어야 합니다.
MySQL에서는 코드 요소를 만들려면, 사용자에게 CREATE
ROUTINE
권한 및 EXECUTE
실행 권한이 있어야 합니다. MySQL DEFINER
절은 코드 객체에 대한 사용자 생성자를 정의하고, 사용자는 CREATE ROUTINE
과 같은 적합한 권한을 보유해야 합니다.
MySQL 저장 프로시저 및 함수 구문
다음 예시는 MySQL 저장 프로시저와 함수 구문을 보여줍니다.
CREATE
[DEFINER = user]
PROCEDURE sp_name ([proc_parameter[,...]])
[characteristic ...] routine_body
CREATE
[DEFINER = user]
FUNCTION sp_name ([func_parameter[,...]])
RETURNS type
[characteristic ...] routine_body
proc_parameter:
[ IN | OUT | INOUT ] param_name type
func_parameter:
param_name type
type:
Any valid MySQL data type
characteristic:
COMMENT 'string'
| LANGUAGE SQL
| [NOT] DETERMINISTIC
| { CONTAINS SQL | NO SQL | READS SQL DATA | MODIFIES SQL DATA }
| SQL SECURITY { DEFINER | INVOKER }
routine_body:
Valid SQL routine statement