:meta-keywords: cubrid type cast :meta-description: CUBRID Arithmetic Operations and Type Casting of Numeric and DATE/TIME Data Types :tocdepth: 3 *********** 산술 연산자 *********** .. contents:: 산술 연산자는 덧셈, 뺄셈, 곱셈, 나눗셈을 위한 이항(binary) 연산자와 양수, 음수를 나타내기 위한 단항(unary) 연산자가 있다. 양수/음수의 부호를 나타내는 단항 연산자의 연산 우선순위가 이항 연산자보다 높다. :: ::= bit_string | character_string | numeric_value | date-time_value | collection_value | NULL ::= | ::= + | - | * | { / | DIV } | { % | MOD } ::= UNION | DIFFERENCE | { INTERSECT | INTERSECTION } * <*expression*>: 연산을 수행할 수식을 선언한다. * <*mathematical_operator*>: 수학적 연산을 지정하는 연산자로서, 산술 연산자와 집합 연산자가 있다. * <*set_arithmetic_operator*>: 컬렉션 타입의 피연산자에 대해 합집합, 차집합, 교집합을 수행하는 집합 산술 연산자이다. * <*arithmetic_operator*>: 사칙 연산을 수행하기 위한 연산자이다. 다음은 CUBRID가 지원하는 산술 연산자의 설명 및 리턴 값을 나타낸 표이다. **산술 연산자** +-------------+--------------------------------------------------------------------------------------+------------+----------------+ | 산술 연산자 | **설명** | 연산식 | 리턴 값 | +=============+======================================================================================+============+================+ | **+** | 더하기 연산 | 1+2 | 3 | +-------------+--------------------------------------------------------------------------------------+------------+----------------+ | **-** | 빼기 연산 | 1-2 | -1 | +-------------+--------------------------------------------------------------------------------------+------------+----------------+ | **\*** | 곱하기 연산 | 1*2 | 2 | +-------------+--------------------------------------------------------------------------------------+------------+----------------+ | **/** | 나누기 연산 후, 몫을 반환한다. | 1/2.0 | 0.500000000 | +-------------+--------------------------------------------------------------------------------------+------------+----------------+ | **DIV** | 나누기 연산 후, 몫을 반환한다. 피연산자는 정수 타입이어야 하며, 정수를 반환한다. | 1 DIV 2 | 0 | +-------------+--------------------------------------------------------------------------------------+------------+----------------+ | **%** | 나누기 연산 후, 나머지를 반환한다. 피연산자는 정수 타입이어야 하며, 정수를 반환한다. | 1 % 2 | 1 | | , | 피연산자가 실수이면 **MOD** | 1 MOD 2 | | | **MOD** | 함수를 이용한다. | | | +-------------+--------------------------------------------------------------------------------------+------------+----------------+ .. _numeric-data-type-op-and-conversion: 수치형 데이터 타입의 산술 연산과 타입 변환 ========================================== 모든 수치형 데이터 타입을 산술 연산에 사용할 수 있으며, 연산 결과 타입은 피연산자의 데이터 타입과 연산의 종류에 따라 다르다. 아래는 피연산자 타입별 덧셈/뺄셈/곱셈 연산의 결과 데이터 타입을 정리한 표이다. **피연산자의 타입별 결과 데이터 타입** +--------------+--------------+--------------+--------------+--------------+ | | **INT** | **NUMERIC** | **FLOAT** | **DOUBLE** | +==============+==============+==============+==============+==============+ | **INT** | INT 또는 | NUMERIC | FLOAT | DOUBLE | | | BIGINT | | | | +--------------+--------------+--------------+--------------+--------------+ | **NUMERIC** | NUMERIC | NUMERIC | DOUBLE | DOUBLE | | | | (p와 s도 | | | | | | 변환됨) | | | +--------------+--------------+--------------+--------------+--------------+ | **FLOAT** | FLOAT | DOUBLE | FLOAT | DOUBLE | +--------------+--------------+--------------+--------------+--------------+ | **DOUBLE** | DOUBLE | DOUBLE | DOUBLE | DOUBLE | +--------------+--------------+--------------+--------------+--------------+ 피연산자가 모두 동일한 데이터 타입이면 연산 결과의 타입이 변환되지 않으나, 나누기 연산의 경우 예외적으로 타입이 변환되므로 주의해야 한다. 분모, 즉 제수(divisor)가 0이면 에러가 발생한다. 아래는 피연산자가 모두 **NUMERIC** 타입인 경우, 연산 결과의 전체 자릿수(*p*)와 소수점 아래 자릿수(*s*)를 정리한 표이다. **NUMERIC 타입의 연산 결과** +-----------------------+---------------------------------------------------------------------------------------------+---------------------------+ | 연산 | 결과의 최대 자릿수 | 결과의 소수점 이하 자릿수 | +=======================+=============================================================================================+===========================+ | N(p1, s1) + N(p2, s2) | max(p1-s1, p2-s2)+max(s1, s2) +1 | max(s1, s2) | +-----------------------+---------------------------------------------------------------------------------------------+---------------------------+ | N(p1, s1) - N(p2, s2) | max(p1-s1, p2-s2)+max(s1, s2) | max(s1, s2) | +-----------------------+---------------------------------------------------------------------------------------------+---------------------------+ | N(p1, s1) * N(p2, s2) | p1+p2+1 | s1+s2 | +-----------------------+---------------------------------------------------------------------------------------------+---------------------------+ | N(p1, s1) / N(p2, s2) | s2 > 0 이면 Pt = p1+max(s1, s2) + s2 - s1, 그 외에는 Pt = p1라 하고, s1 > s2 이면 St = s1, | | | 그 외에는 s2라 하면, 소수점 이하 자릿수는 St < 9 이면 min(9-St, 38-Pt) + St, 그 외에는 St | +-----------------------+---------------------------------------------------------------------------------------------+---------------------------+ **예제** .. code-block:: sql --int * int SELECT 123*123; :: 123*123 ============= 15129 .. code-block:: sql -- int * int returns overflow error SELECT (1234567890123*1234567890123); :: ERROR: Data overflow on data type bigint. .. code-block:: sql -- int * numeric returns numeric type SELECT (1234567890123*CAST(1234567890123 AS NUMERIC(15,2))); :: (1234567890123* cast(1234567890123 as numeric(15,2))) ====================== 1524157875322755800955129.00 .. code-block:: sql -- int * float returns float type SELECT (1234567890123*CAST(1234567890123 AS FLOAT)); :: (1234567890123* cast(1234567890123 as float)) =============================================== 1.524158e+024 .. code-block:: sql -- int * double returns double type SELECT (1234567890123*CAST(1234567890123 AS DOUBLE)); :: (1234567890123* cast(1234567890123 as double)) ================================================ 1.524157875322756e+024 .. code-block:: sql -- numeric * numeric returns numeric type SELECT (CAST(1234567890123 AS NUMERIC(15,2))*CAST(1234567890123 AS NUMERIC(15,2))); :: ( cast(1234567890123 as numeric(15,2))* cast(1234567890123 as numeric(15,2))) ====================== 1524157875322755800955129.0000 .. code-block:: sql -- numeric * float returns double type SELECT (CAST(1234567890123 AS NUMERIC(15,2))*CAST(1234567890123 AS FLOAT)); :: ( cast(1234567890123 as numeric(15,2))* cast(1234567890123 as float)) ======================================================================= 1.524157954716582e+024 .. code-block:: sql -- numeric * double returns double type SELECT (CAST(1234567890123 AS NUMERIC(15,2))*CAST(1234567890123 AS DOUBLE)); :: ( cast(1234567890123 as numeric(15,2))* cast(1234567890123 as double)) ======================================================================== 1.524157875322756e+024 .. code-block:: sql -- float * float returns float type SELECT (CAST(1234567890123 AS FLOAT)*CAST(1234567890123 AS FLOAT)); :: ( cast(1234567890123 as float)* cast(1234567890123 as float)) =============================================================== 1.524158e+024 .. code-block:: sql -- float * double returns float type SELECT (CAST(1234567890123 AS FLOAT)*CAST(1234567890123 AS DOUBLE)); :: ( cast(1234567890123 as float)* cast(1234567890123 as double)) ================================================================ 1.524157954716582e+024 .. code-block:: sql -- double * double returns float type SELECT (CAST(1234567890123 AS DOUBLE)*CAST(1234567890123 AS DOUBLE)); :: ( cast(1234567890123 as double)* cast(1234567890123 as double)) ================================================================= 1.524157875322756e+024 .. code-block:: sql -- int / int returns int type without type conversion or rounding SELECT 100100/100000; :: 100100/100000 =============== 1 .. code-block:: sql -- int / int returns int type without type conversion or rounding SELECT 100100/200200; :: 100100/200200 =============== 0 .. code-block:: sql -- int / zero returns error SELECT 100100/(100100-100100); :: ERROR: Attempt to divide by zero. .. _arithmetic-op-type-casting: 날짜/시간 데이터 타입의 산술 연산과 타입 변환 ============================================= 피연산자가 모두 날짜/시간 데이터 타입이면 뺄셈 연산이 가능하며, 리턴 값의 타입은 **BIGINT** 이다. 이때 피연산자의 타입에 따라 연산 단위가 다르므로 주의한다. 날짜/시간 데이터 타입과 정수는 덧셈 및 뺄셈 연산이 가능하며, 이때 연산 단위와 리턴 값의 타입은 날짜/시간 데이터 타입을 따른다. 아래는 피연산자의 타입별로 허용하는 연산과 연산 결과의 데이터 타입을 정리한 표이다. **피연산자의 타입별 허용 연산과 결과 데이터 타입** +---------------+------------------+------------------+---------------------+--------------------+-----------------------+ | | TIME | DATE | TIMESTAMP | DATETIME | INT | | | (초 단위) | (일 단위) | (초 단위) | (밀리초 단위) | | +===============+==================+==================+=====================+====================+=======================+ | **TIME** | 뺄셈만 허용. | X | X | X | 덧셈, 뺄셈 허용. | | | **BIGINT** | | | | **TIME** | +---------------+------------------+------------------+---------------------+--------------------+-----------------------+ | **DATE** | X | 뺄셈만 허용. | 뺄셈만 허용. | 뺄셈만 허용. | 덧셈, 뺄셈 허용. | | | | **BIGINT** | **BIGINT** | **BIGINT** | **DATE** | +---------------+------------------+------------------+---------------------+--------------------+-----------------------+ | **TIMESTAMP** | X | 뺄셈만 허용. | 뺄셈만 허용. | 뺄셈만 허용. | 덧셈, 뺄셈 허용. | | | | **BIGINT** | **BIGINT** | **BIGINT** | **TIMESTAMP** | +---------------+------------------+------------------+---------------------+--------------------+-----------------------+ | **DATETIME** | X | 뺄셈만 허용. | 뺄셈만 허용. | 뺄셈만 허용. | 덧셈, 뺄셈 허용. | | | | **BIGINT** | **BIGINT** | **BIGINT** | **DATETIME** | +---------------+------------------+------------------+---------------------+--------------------+-----------------------+ | **INT** | 덧셈, 뺄셈 허용 | 덧셈, 뺄셈 허용. | 덧셈, 뺄셈 허용. | 덧셈, 뺄셈 허용. | 모든 산술 연산 허용 | | | **TIME** | **DATE** | **TIMESTAMP** | **DATETIME** | | +---------------+------------------+------------------+---------------------+--------------------+-----------------------+ .. note:: 날짜/시간 산술 연산의 인자 중 하나라도 **NULL** 이 포함되어 있으면 수식의 결과로 **NULL** 이 반환된다. **예제** .. code-block:: sql -- initial systimestamp value SELECT SYSDATETIME; :: SYSDATETIME =============================== 07:09:52.115 PM 01/14/2010 .. code-block:: sql -- time type + 10(seconds) returns time type SELECT (CAST (SYSDATETIME AS TIME) + 10); :: ( cast( SYS_DATETIME as time)+10) ==================================== 07:10:02 PM .. code-block:: sql -- date type + 10 (days) returns date type SELECT (CAST (SYSDATETIME AS DATE) + 10); :: ( cast( SYS_DATETIME as date)+10) ==================================== 01/24/2010 .. code-block:: sql -- timestamp type + 10(seconds) returns timestamp type SELECT (CAST (SYSDATETIME AS TIMESTAMP) + 10); :: ( cast( SYS_DATETIME as timestamp)+10) ========================================= 07:10:02 PM 01/14/2010 .. code-block:: sql -- systimestamp type + 10(milliseconds) returns systimestamp type SELECT (SYSDATETIME + 10); :: ( SYS_DATETIME +10) =============================== 07:09:52.125 PM 01/14/2010 .. code-block:: sql SELECT DATETIME '09/01/2009 03:30:30.001 pm'- TIMESTAMP '08/31/2009 03:30:30 pm'; :: datetime '09/01/2009 03:30:30.001 pm'-timestamp '08/31/2009 03:30:30 pm' ======================================= 86400001 .. code-block:: sql SELECT TIMESTAMP '09/01/2009 03:30:30 pm'- TIMESTAMP '08/31/2009 03:30:30 pm'; :: timestamp '09/01/2009 03:30:30 pm'-timestamp '08/31/2009 03:30:30 pm' ======================================= 86400 타임존 파라미터들과 관련된 동작 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ TIMESTAMP 및 TIMESTAMP WITH LOCAL TIME ZONE 데이터 타입은 내부적으로 UNIX epoch 값(1970년 이후 경과한 시간(초))으로 저장되며, 윤초를 사용(tz_leap_second_support가 yes로 설정, :ref:`timezone-parameters` 참고)할 경우 가상 날짜-시간 값을 포함할 수 있다. .. code-block:: sql Virtual date-time Unix timestamp 2008-12-31 23:59:58 -> 79399951 2008-12-31 23:59:59 -> 79399952 2008-12-31 23:59:60 -> 79399953 -> not real date (introduced by leap second) 2009-01-01 00:00:00 -> 79399954 2009-01-01 00:00:01 -> 79399955 TIMESTAMP 및 TIMESTAMPLTZ 값이 포함된 산술 연산은 Unix epoch 값에서 바로 수행되며, 존재하지 않는 날짜/시간 값에 해당하는 Unix epoch 값이 허용된다. .. code-block:: sql SELECT TIMESTAMPLTZ'2008-12-31 23:59:59 UTC'=TIMESTAMPLTZ'2008-12-31 23:59:59 UTC'+1; :: timestampltz '2008-12-31 23:59:59 UTC'=timestampltz '2008-12-31 23:59:59 UTC'+1 ================================================================================= 0 따라서 위의 비교는 Unix 타임스탬프 79399952와 79399953을 비교하는 것과 같지만 동일한 값이 TIMESTAMPTZ로 사용되면 다음과 같이 동일하다. .. code-block:: sql SELECT TIMESTAMPTZ'2008-12-31 23:59:59 UTC'=TIMESTAMPTZ'2008-12-31 23:59:59 UTC'+1; :: timestamptz '2008-12-31 23:59:59 UTC'=timestamptz '2008-12-31 23:59:59 UTC'+1 =============================================================================== 1 화면에는 다음과 같은 불일치가 나타난다. .. code-block:: sql SELECT TIMESTAMPLTZ'2008-12-31 23:59:59 UTC'+1; :: timestampltz '2008-12-31 23:59:59 UTC'+1 ============================================= 11:59:59 PM 12/31/2008 Etc/UTC UTC Unix 타임스탬프 값 79399953과 관련된 '2008-12-31 23:59:60 UTC는 실제 날짜가 아니기 때문에 바로 이전 값이 사용되지만 내부적으로는 '2008-12-31 23:59:60 UTC’ 값과 동일하다. TIMESTAMP WITH TIME ZONE 데이터 타입은 UNIX 타임스탬프와 타임존 식별자를 모두 포함한다. UNIX 타임스탬프 부분 값에서도 TIMESTAMPTZ에 대한 연산을 수행할 수 있으나, 이 경우 자동 조정 연산이 이어서 수행된다. 지역, 오프셋, 서머타임 등의 타임존 식별자를 포함하려면 TIMESTAMPTZ 객체의 날짜-시간이 유효해야 한다. timestamptz'2008-12-31 23:59:59 UTC'+1의 경우 유효하지 않은 날짜-시간(79399953,UTC) 대신 '2008-12-31 23:59:59 UTC'에 해당하는 (79399952,UTC)로 자동 변환된다. DATETIMETZ 및 TIMESTAMPTZ를 포함하는 산술 연산 후에는, CUBRID에서 다음과 관련된 결과 값의 자동 조정을 수행한다. - 타임존 식별자 조정: 타임존이 포함된 날짜에 시간(초)을 더하면 내부적으로 저장된 오프셋 규칙과 서머타임 규칙이 변경될 수 있으므로, 이에 따라 타임존 식별자를 갱신 한다. - Unix 타임스탬프 조정(TIMESTAMPTZ에만 해당): 가상의 날짜-시간 값(윤초가 활성화된 경우)이 항상 바로 이전 Unix 타임스탬프 값으로 변환된다.