Loading...
MySQL 9.5 Reference Manual 9.5의 14.3 Type Conversion in Expression Evaluation의 한국어 번역본입니다.
아래의 경우에 피드백에서 신고해주신다면 반영하겠습니다.
감사합니다 :)
연산자가 서로 다른 type의 operand와 함께 사용되면, operand를 호환되게 만들기 위해 type conversion이 발생합니다. 일부 conversion은 암시적으로 발생합니다. 예를 들어, MySQL은 필요에 따라 문자열을 숫자로, 그리고 그 반대로 자동으로 변환합니다.
1mysql> SELECT 1+'1'; 2 -> 2 3mysql> SELECT CONCAT(2,' test'); 4 -> '2 test'
CAST() function을 사용하여 숫자를 문자열로 명시적으로 변환하는 것도 가능합니다. CONCAT() function은 문자열 argument를 기대하므로, 이 function에서는 conversion이 암시적으로 발생합니다.
1mysql> SELECT 38.8, CAST(38.8 AS CHAR); 2 -> 38.8, '38.8' 3mysql> SELECT 38.8, CONCAT(38.8); 4 -> 38.8, '38.8'
암시적인 숫자-문자열 변환의 character set에 대한 정보와, CREATE TABLE ... SELECT statement에 적용되는 수정된 규칙에 대해서는 이 절의 뒷부분을 참조하십시오.
다음 규칙은 comparison 연산에서 conversion이 어떻게 발생하는지 설명합니다:
하나 또는 양쪽 argument가 NULL인 경우, 비교 결과는 NULL입니다. 단, NULL-safe <=> equality comparison operator는 예외입니다. NULL <=> NULL의 결과는 true입니다. 이 경우 conversion은 필요하지 않습니다.
comparison 연산에서 두 argument가 모두 문자열이면, 문자열로 비교됩니다.
두 argument가 모두 integer이면, integer로 비교됩니다.
hexadecimal 값은 숫자와 비교되지 않는 한 binary 문자열로 취급됩니다.
argument 중 하나가 TIMESTAMP 또는 DATETIME column이고 다른 argument가 상수인 경우, 비교가 수행되기 전에 상수는 timestamp로 변환됩니다. 이는 ODBC 친화성을 높이기 위해 수행됩니다. 이 동작은 IN()의 argument에는 적용되지 않습니다. 안전을 위해, comparison을 수행할 때는 항상 완전한 datetime, date, time 문자열을 사용하십시오. 예를 들어, date나 time 값을 사용하여 BETWEEN를 사용할 때 최선의 결과를 얻으려면, CAST()를 사용하여 값을 원하는 data type으로 명시적으로 변환하십시오.
table 또는 여러 table로부터의 single-row subquery는 상수로 간주되지 않습니다. 예를 들어, 어떤 subquery가 DATETIME 값과 비교될 integer를 반환하는 경우, 비교는 두 integer로 수행됩니다. integer는 temporal 값으로 변환되지 않습니다. operand를 DATETIME 값으로 비교하려면, CAST()를 사용하여 subquery 값을 DATETIME으로 명시적으로 변환하십시오.
argument 중 하나가 decimal 값인 경우, 비교는 다른 argument에 따라 달라집니다. 다른 argument가 decimal 또는 integer 값이면 decimal 값으로 비교되고, 다른 argument가 floating-point 값이면 floating-point 값으로 비교됩니다.
기타 모든 경우에, argument는 floating-point(double-precision) 숫자로 비교됩니다. 예를 들어, 문자열 operand와 numeric operand의 비교는 floating-point 숫자의 비교로 수행됩니다.
한 temporal type에서 다른 temporal type으로의 값 변환에 대한 정보는 Section 13.2.8, “Conversion Between Date and Time Types”를 참조하십시오.
JSON 값의 비교는 두 단계로 수행됩니다. 첫 번째 단계의 비교는 비교되는 값의 JSON type에 기반합니다. type이 다르면, 어떤 type이 더 높은 우선순위를 갖는지에 따라서만 비교 결과가 결정됩니다. 두 값이 동일한 JSON type을 가지면, 두 번째 단계에서 type별 규칙을 사용하여 비교가 수행됩니다. JSON 값과 non-JSON 값의 비교에서는, non-JSON 값이 JSON으로 변환되고 값이 JSON 값으로서 비교됩니다. 자세한 내용은 Comparison and Ordering of JSON Values를 참조하십시오.
다음 예는 comparison 연산에서 문자열이 숫자로 변환되는 방식을 보여 줍니다:
1mysql> SELECT 1 > '6x'; 2 -> 0 3mysql> SELECT 7 > '6x'; 4 -> 1 5mysql> SELECT 0 > 'x6'; 6 -> 0 7mysql> SELECT 0 = 'x6'; 8 -> 1
문자열 column과 숫자의 비교에서는, MySQL이 해당 column의 index를 사용하여 값을 빠르게 조회할 수 없습니다. 만약 _str_col_이 index가 있는 문자열 column이라면, 다음 statement에서 lookup을 수행할 때 index를 사용할 수 없습니다:
1SELECT * FROM tbl_name WHERE str_col=1;
이는 1로 변환될 수 있는 서로 다른 문자열이 매우 많기 때문입니다. 예를 들어 '1', ' 1', 또는 '1a' 등이 있습니다.
또 다른 문제는 문자열 column을 integer 0과 비교할 때 발생할 수 있습니다. 다음과 같이 table t1을 생성하고 데이터를 채운다고 가정해 보겠습니다:
1mysql> CREATE TABLE t1 ( 2 -> c1 INT NOT NULL AUTO_INCREMENT, 3 -> c2 INT DEFAULT NULL, 4 -> c3 VARCHAR(25) DEFAULT NULL, 5 -> PRIMARY KEY (c1) 6 -> ); 7Query OK, 0 rows affected (0.03 sec) 8 9mysql> INSERT INTO t1 VALUES ROW(1, 52, 'grape'), ROW(2, 139, 'apple'), 10 -> ROW(3, 37, 'peach'), ROW(4, 221, 'watermelon'), 11 -> ROW(5, 83, 'pear'); 12Query OK, 5 rows affected (0.01 sec) 13Records: 5 Duplicates: 0 Warnings: 0
VARCHAR column인 c3를 integer 0과 비교하여 이 table에서 select할 때의 결과를 살펴보십시오:
1mysql> SELECT * FROM t1 WHERE c3 = 0; 2+----+------+------------+ 3| c1 | c2 | c3 | 4+----+------+------------+ 5| 1 | 52 | grape | 6| 2 | 139 | apple | 7| 3 | 37 | peach | 8| 4 | 221 | watermelon | 9| 5 | 83 | pear | 10+----+------+------------+ 115 rows in set, 5 warnings (0.00 sec)
이는 strict SQL mode를 사용하더라도 발생합니다. 이 상황을 방지하려면, 다음과 같이 값을 quote 하십시오:
1mysql> SELECT * FROM t1 WHERE c3 = '0'; 2Empty set (0.00 sec)
이 문제는 [SELECT](https://dev.mysql.com/doc/refman/9.5/en/select.html "15.2.13 SELECT Statement)가 CREATE TABLE\ ... SELECT와 같은 data definition statement의 일부일 때는 발생하지 않습니다. strict mode에서는, 잘못된 comparison으로 인해 statement가 실패합니다:
1mysql> CREATE TABLE t2 SELECT * FROM t1 WHERE c3 = 0; 2ERROR 1292 (22007): Truncated incorrect DOUBLE value: 'grape'
0을 quote하면 statement는 성공하지만, '0'과 일치하는 row가 없었기 때문에 생성된 table에는 row가 포함되지 않습니다. 다음 예와 같습니다:
1mysql> CREATE TABLE t2 SELECT * FROM t1 WHERE c3 = '0'; 2Query OK, 0 rows affected (0.03 sec) 3Records: 0 Duplicates: 0 Warnings: 0 4 5mysql> SELECT * FROM t2; 6Empty set (0.00 sec)
이는 알려진 issue이며, strict mode가 SELECT를 처리할 때는 적용되지 않기 때문입니다. 또한 Strict SQL Mode를 참조하십시오.
floating-point 숫자와 큰 integer 값 사이의 비교는 근사값 비교입니다. 이는 비교 전에 integer가 double-precision floating point로 변환되며, double-precision이 모든 64-bit integer를 정확하게 표현할 수 없기 때문입니다. 예를 들어, integer 값 253 + 1은 float로 표현할 수 없으며, platform에 따라 float 비교 전에 253 또는 253 + 2로 반올림됩니다.
이를 설명하기 위해, 다음 비교들 중 첫 번째 비교만이 동일한 값을 비교하지만, 두 비교 모두 true(1)을 반환합니다:
1mysql> SELECT '9223372036854775807' = 9223372036854775807; 2 -> 1 3mysql> SELECT '9223372036854775807' = 9223372036854775806; 4 -> 1
문자열에서 floating-point로의 변환과 integer에서 floating-point로의 변환이 발생할 때, 두 변환은 반드시 동일한 방식으로 수행되지는 않습니다. integer는 CPU에 의해 floating-point로 변환될 수 있는 반면, 문자열은 floating-point 곱셈이 수반되는 연산에서 자릿수별로 변환됩니다. 또한, 결과는 computer architecture, compiler version, optimization level과 같은 요인에 의해 영향을 받을 수 있습니다. 이러한 문제를 피하는 한 가지 방법은 CAST()를 사용하여 값이 암시적으로 float-point 숫자로 변환되지 않도록 하는 것입니다:
1mysql> SELECT CAST('9223372036854775807' AS UNSIGNED) = 9223372036854775806; 2 -> 0
floating-point 비교에 대한 자세한 내용은 Section B.3.4.8, “Problems with Floating-Point Values”를 참조하십시오.
server에는 dtoa라는 conversion library가 포함되어 있으며, 이는 문자열 또는 DECIMAL 값과 approximate-value (FLOAT/ DOUBLE) 숫자 사이의 변환을 향상시키는 기반을 제공합니다:
platform 간에 일관된 conversion 결과를 제공하여, 예를 들어 Unix와 Windows 사이의 conversion 차이를 제거합니다.
이전에 충분한 precision을 제공하지 못했던 결과(예: IEEE limit에 가까운 값)에 대해 값의 정확한 표현을 제공합니다.
가능한 최상의 precision으로 숫자를 문자열 형식으로 변환합니다. dtoa의 precision은 표준 C library function의 precision과 같거나 더 좋습니다.
이 library가 생성하는 conversion은 일부 경우 non-dtoa 결과와 다르기 때문에, 이전 결과에 의존하는 application에서 호환성 문제가 발생할 수 있습니다. 예를 들어, 이전 conversion에서 특정한 정확한 결과에 의존하는 application은 추가 precision을 수용하도록 조정이 필요할 수 있습니다.
dtoa library는 다음과 같은 property를 가진 conversion을 제공합니다. _D_는 DECIMAL 또는 문자열 표현을 가진 값을 나타내고, _F_는 native binary(IEEE) 형식의 floating-point 숫자를 나타냅니다.
F -> D conversion은 가능한 최상의 precision으로 수행되며, _F_를 다시 읽어서 native binary 형식(IEEE에서 지정한 대로)에서 가장 가까운 값으로 round했을 때 _F_를 생성하는 가장 짧은 문자열인 _D_를 반환합니다.
D -> F conversion은 _F_가 입력 decimal 문자열 _D_에 가장 가까운 native binary 숫자가 되도록 수행됩니다.
이러한 property는 F -> D -> F conversion이 _F_가 -inf, +inf, 또는 NaN이 아닌 한 lossless임을 의미합니다. 후자의 값은 SQL standard가 이를 FLOAT 또는 DOUBLE에 대해 invalid 값으로 정의하기 때문에 지원되지 않습니다.
D -> F -> D conversion의 경우, lossless가 되기 위한 충분 조건은 _D_가 precision 15자리 이하를 사용하고, denormal 값, -inf, +inf, NaN이 아니어야 한다는 것입니다. 일부 경우에는 _D_가 precision 15자리보다 많더라도 conversion이 lossless일 수 있지만, 항상 그런 것은 아닙니다.
numeric 또는 temporal 값을 문자열로 암시적으로 변환하면, 변환 결과 값은 character_set_connection 및 collation_connection system variable에 의해 결정되는 character set과 collation을 갖게 됩니다. (이 variable은 일반적으로 SET NAMES로 설정됩니다. connection character set에 대한 정보는 Section 12.4, “Connection Character Sets and Collations”를 참조하십시오.)
이는 이러한 conversion이 connection character set이 binary로 설정된 경우를 제외하고는 character(nonbinary) 문자열(CHAR, VARCHAR, LONGTEXT 값)을 결과로 생성함을 의미합니다. connection character set이 binary인 경우에는 변환 결과가 BINARY, VARBINARY, LONGBLOB 값과 같은 binary 문자열이 됩니다.
integer expression의 경우, 앞에서 언급한 표현식 _평가_에 대한 설명은 다음과 같은 statement에서처럼 표현식 _할당_의 경우 다소 다르게 적용됩니다:
1CREATE TABLE t SELECT integer_expr;
이 경우, 표현식으로부터 생성되는 column이 있는 table은 integer expression의 길이에 따라 INT 또는 BIGINT type을 갖습니다. expression의 최대 길이가 INT에 맞지 않으면, 대신 BIGINT가 사용됩니다. 길이는 SELECT result set metadata의 max_length 값에서 가져옵니다(C API Basic Data Structures 참조). 이는 충분히 긴 표현식을 사용하여 INT 대신 BIGINT을 강제할 수 있음을 의미합니다:
1CREATE TABLE t SELECT 000000000000000000000;
14.2 Loadable Function Reference
14.4 Operators