source

CASE 문과 DECODE가 동일합니까?

factcode 2023. 6. 28. 22:01
반응형

CASE 문과 DECODE가 동일합니까?

단순 CASE 표현식과 DECODE 기능이 동일하며 이들이 반환하는 결과는 동일해야 합니다.그래요?

설명서에는 간단한 CASE 표현식에 대해 다음과 같이 나와 있습니다.

simple CASE 식은 selector_value가 selector와 일치하는 첫 번째 결과를 반환합니다.나머지 식은 평가되지 않습니다.selector_value가 selector와 일치하는 항목이 없으면 CASE 식은 else_result를 반환하고 그렇지 않으면 NULL을 반환합니다.

를 DECODE 기능과 비교하면 설명이 동일한 것 같습니다.

DECODE는 expr을 각 검색 값과 하나씩 비교합니다.expr이 검색과 동일한 경우 Oracle Database는 해당 결과를 반환합니다.일치하는 항목이 없으면 Oracle은 기본값을 반환합니다.기본값을 생략하면 Oracle은 null을 반환합니다.

검색된 CASE 표현식이 단순 표현식과 동일할 수 있으므로 이 표현식도 마찬가지로 해석될 수 있습니다.

이 세 개의 문은 모두 동일한 결과인 0을 반환하는 것 같습니다.

select case 1 when 2 then null else 0 end as simple_case
     , case when 1 = 2 then null else 0 end as searched_case
     , decode(1, 2, null, 0) as decode
  from dual

단순 CASE 식과 DECODE 기능(및 특정 상황에서 검색된 CASE 식)이 항상 동일한 결과를 반환합니까?

단답, 아니요.

조금 더 긴 대답은 거의 입니다.

각 문에서 얻은 결과가 동일한 것으로만 나타납니다.DUMP 기능을 사용하여 반환되는 데이터 유형을 평가하면 다음과 같은 의미를 알 수 있습니다.

SQL> select dump(case 1 when 2 then null else 0 end) as simple_case
  2       , dump(case when 1 = 2 then null else 0 end) as searched_case
  3       , dump(decode(1, 2, null, 0)) as decode
  4    from dual;

SIMPLE_CASE        SEARCHED_CASE      DECODE
------------------ ------------------ -----------------
Typ=2 Len=1: 128   Typ=2 Len=1: 128   Typ=1 Len=1: 48

SQL 피들

DECODE의 데이터 유형은 1인 반면, 두 CASE 문은 2의 데이터 유형을 "반환"하는 것을 볼 수 있습니다.Oracle의 Data Type Summary를 사용하여 DECODE는 VARCHAR2(데이터 유형 1)를 반환하고 CASE 문은 숫자를 "반환"(데이터 유형 2)를 반환합니다.

이름에서 알 수 있듯이 DECODE는 기능이고 CASE는 기능이 아니기 때문에 내부적으로 다르게 구현되었기 때문에 이러한 현상이 발생한다고 생각합니다.이것을 증명할 실질적인 방법은 없습니다.

여러분은 이것이 실제로 아무 영향도 주지 않는다고 생각할 수 있습니다.숫자가 필요한 경우 Oracle은 암묵적인 변환 규칙에 따라 문자를 숫자로 암시적으로 변환합니다. 그렇죠?이 역시 사실이 아닙니다. 데이터 유형이 동일해야 하기 때문에 연합에서는 작동하지 않습니다. Oracle은 사용자가 쉽게 작업할 수 있도록 암묵적인 변환을 수행하지 않습니다.두 번째로, Oracle은 암묵적인 변환에 대해 다음과 같이 말합니다.

Oracle은 다음과 같은 이유로 암묵적 또는 자동 변환에 의존하지 말고 명시적 변환을 지정하는 것이 좋습니다.

  • SQL 문은 명시적 데이터 형식 변환 함수를 사용할 때 더 쉽게 이해할 수 있습니다.

  • 특히 열 값의 데이터 유형이 그 반대가 아닌 상수 값의 데이터 유형으로 변환되는 경우 암묵적인 데이터 유형 변환은 성능에 부정적인 영향을 미칠 수 있습니다.

  • 암시적 변환은 발생하는 상황에 따라 달라지며 모든 경우에 동일한 방식으로 작동하지 않을 수 있습니다.예를 들어 날짜/시간 값에서 VARCHAR2 값으로 암시적으로 변환하면 NLS_DATE_FORMAT 매개 변수 값에 따라 예기치 않은 연도가 반환될 수 있습니다.

  • 암시적 변환 알고리즘은 소프트웨어 릴리스와 오라클 제품 간에 변경될 수 있습니다.명시적 변환의 동작은 더 예측 가능합니다.

그것은 예쁜 목록이 아닙니다. 하지만 끝에서 끝까지 가는 점이 저에게 데이트를 멋지게 해줍니다.이전 쿼리를 사용하여 대신 날짜를 사용하는 쿼리로 변환하는 경우:

select case sysdate when trunc(sysdate) then null 
                    else sysdate 
       end as simple_case
     , case when sysdate = trunc(sysdate) then null 
            else sysdate 
       end as searched_case
     , decode(sysdate, trunc(sysdate), null, sysdate) as decode
  from dual;

다시 한 번 이 쿼리에서 DUMP를 사용하면 CASE 문은 데이터 유형 12, DATE를 반환합니다.가 DECODE를 변환했습니다.sysdateVARCHAR2로 이동합니다.

SQL> select dump(case sysdate when trunc(sysdate) then null
  2                           else sysdate
  3              end) as simple_case
  4       , dump(case when sysdate = trunc(sysdate) then null
  5                   else sysdate
  6              end) as searched_case
  7       , dump(decode(sysdate, trunc(sysdate), null, sysdate)) as decode
  8    from dual;

SIMPLE_CASE          
---------------------------------- 
Typ=12 Len=7: 120,112,12,4,22,18,7 
SEARCHED_CASE
---------------------------------- 
Typ=12 Len=7: 120,112,12,4,22,18,7
DECODE
---------------------------------- 
Typ=1 Len=19: 50,48,49,50,45,49,50,45,48,52,32,50,49,58,49,55,58,48,54

SQL 피들

SQL Fiddle에서 DATE가 NLS_DATE_FORMAT 세션을 사용하여 문자로 변환되었습니다.

VARCHAR2로 암묵적으로 변환된 날짜가 있으면 문제가 발생할 수 있습니다.TO_CHAR을 사용하여 날짜를 문자로 변환하려는 경우 예상치 못한 부분에서 쿼리가 중단됩니다.

SQL> select to_char( decode( sysdate
  2                         , trunc(sysdate), null
  3                         , sysdate )
  4                 , 'yyyy-mm-dd') as to_char
  5    from dual;
select to_char( decode( sysdate
                *
ERROR at line 1:
ORA-01722: invalid number

SQL 피들

마찬가지로 날짜 산술은 더 이상 작동하지 않습니다.

SQL>
SQL>
SQL> select decode(sysdate, trunc(sysdate), null, sysdate) + 1 as decode
  2    from dual;
select decode(sysdate, trunc(sysdate), null, sysdate) + 1 as decode
       *
ERROR at line 1:
ORA-01722: invalid number

SQL 피들

흥미롭게도 DECODE는 가능한 결과 중 하나가 NULL인 경우에만 식을 VARCHAR2로 변환합니다.기본값이 NULL이면 이 작업이 수행되지 않습니다.예를 들어:

SQL> select decode(sysdate, sysdate, sysdate, null) as decode
  2    from dual;

DECODE
-------------------
2012-12-04 21:18:32

SQL> select dump(decode(sysdate, sysdate, sysdate, null)) as decode
  2    from dual;

DECODE
------------------------------------------    
Typ=13 Len=8: 220,7,12,4,21,18,32,0

SQL 피들

DECODE는 13의 데이터 유형을 반환했습니다.이것은 문서화되지 않았지만 날짜 산술 등이 작동하는 날짜 유형입니다.

간단히 말해서, 가능하면 DECODE를 사용하지 마십시오. 원하는 데이터 유형을 얻을 수 없을 수도 있습니다.Tom Kyte의 말을 인용하자면:

디코딩은 다소 모호합니다. CASE는 매우 명확합니다.디코딩에서 쉽게 수행할 수 있는 작업은 경우에 따라 쉽게 수행할 수 있으며, 디코딩으로 수행하기 어렵거나 거의 불가능한 작업은 경우에 따라 수행할 수 있습니다.논리적으로 보면 CASE가 승리합니다.


DECODE와 CASE 사이에는 두 가지 기능적 차이가 있습니다.

  1. PL/SQL 내에서는 DECODE를 사용할 수 없습니다.
  2. CASE를 사용하여 null을 직접 비교할 수 없습니다.

    SQL> select case null when null then null else 1 end as case1
      2        , case when null is null then null else 1 end as case2
      3        , decode(null, null, null, 1) as decode
      4    from dual
      5         ;
    
         CASE1      CASE2 DECODE
    ---------- ---------- ------
             1
    

    SQL 피들

Ben은 DECODE와 CASE의 차이점에 대해 장황한 답변을 작성했습니다.그는 DECODE와 CASE가 동일한 값 집합에 대해 서로 다른 데이터 유형을 반환할 수 있다는 것을 보여줍니다. 이러한 이유를 제대로 설명하지 않아도 됩니다.

DECODE()는 매우 규범적입니다. 항상 첫 번째 결과 파라미터의 데이터 유형입니다.Oracle은 다른 모든 결과 매개 변수에 암시적 변환을 적용합니다.첫 번째 결과 매개 변수가 숫자이고 기본값이 날짜인 경우 오류가 발생합니다.

ORA-00932: inconsistent datatypes: expected NUMBER got DATE

자세한 내용은 설명서에 설명되어 있습니다.

첫 번째 시나리오에서 첫 번째 결과 매개 변수는 NULL이며, Oracle은 이 매개 변수를 VARCHAR2로 처리하기로 결정합니다.첫 번째 결과 파라미터가 숫자이고 기본값이 null이 되도록 변경하면 DECODE() 문이 NUMBER를 반환합니다. DUMP()는 이를 증명합니다.

반면 CASE는 반환된 모든 값이 동일한 데이터 유형을 가지고 있으며 그렇지 않으면 컴파일 오류를 발생시킵니다.암시적 변환이 적용되지 않습니다.이에 대해서는 설명서에서도 다룹니다.여기서 읽어보세요.

그 차이는 결국 이것으로 귀결됩니다.다음 DECODE 문은 실행되지만 CASE 문은 실행되지 않습니다.

select decode(1, 1, 1, '1') from dual;

select case 1 when 1 then 1 else '1' end from dual;

필수 SQL Fiddle입니다.

제가 너무 늦었다는 것을 알지만, 누군가가 그것을 검색한다면 도움이 될 수 있기 때문에 여기에 게시합니다.저는 같은 용도로 MsSql 스크립트를 만들었습니다.

Declare @Var varchar(399)='DECODE(MyColumnName,''A'',''Auto'',''M'',''Manual'')'

Begin
Declare @Count int, @Counter int=1
Declare @TempTable table (ID int identity(1,1),Items varchar(500))
Declare @SqlText varchar(max)
Select @Var=Replace(Replace(@Var,'DECODE(',''),')','')

Insert Into @TempTable
Select * FROM [dbo].[Split] ( @Var ,',')
--Select * from @TempTable
Select @Count=Count(ID) from @TempTable

While(@Counter<=@Count)
Begin
    If(@Counter=1)
    Begin
    Select @SqlText='Case ' +Items from @TempTable Where ID=1
    End

    Else If(@Counter=@Count)
    Begin
    Select @SqlText+=' Then ' +Items +' End' from @TempTable Where ID=@Counter 
    End

    Else If(@Counter%2=0)
    Begin
    Select @SqlText +=' When ' +Items from @TempTable Where ID=@Counter
    End

    Else If(@Counter%2=1)
    Begin
    Select @SqlText +=' Then ' +Items from @TempTable Where ID=@Counter
    End

    Set @Counter+=1
End

Select @SqlText SqlServerCaseStatement
End

위 스크립트에서 분할 함수를 사용했는데, 해당 함수가 필요하면 Romil의 답변을 참조할 수 있습니다 - 쉼표로 구분된 값을 열로 분할하는 방법

언급URL : https://stackoverflow.com/questions/13712763/are-a-case-statement-and-a-decode-equivalent

반응형