Oracle PL/SQL 문자열 비교 문제
다음과 같은 Oracle PL/SQL 코드가 있습니다. 여러분의 관점에서 볼 때 녹슬 수 있습니다.
DECLARE
str1 varchar2(4000);
str2 varchar2(4000);
BEGIN
str1:='';
str2:='sdd';
IF(str1<>str2) THEN
dbms_output.put_line('The two strings is not equal');
END IF;
END;
/
이것은 str1과 str2 두 문자열이 동일하지 않다는 것이 매우 명백한데, 왜 '두 문자열이 동일하지 않음'이 출력되지 않았습니까?오라클에서 두 문자열을 비교하는 다른 일반적인 방법이 있습니까?
Phil이 지적했듯이 빈 문자열은 NULL로 처리되며 NULL은 어떤 문자열과도 같거나 같지 않습니다.빈 문자열이나 NULL이 필요한 경우 다음을 사용하여 처리해야 합니다.NVL()
:
DECLARE
str1 varchar2(4000);
str2 varchar2(4000);
BEGIN
str1:='';
str2:='sdd';
-- Provide an alternate null value that does not exist in your data:
IF(NVL(str1,'X') != NVL(str2,'Y')) THEN
dbms_output.put_line('The two strings are not equal');
END IF;
END;
/
null 비교 관련:
NULLS에 대한 Oracle 12c 문서에 따르면, 다음을 사용한 Null 비교IS NULL
또는IS NOT NULL
을 평가합니다.TRUE
또는FALSE
그러나 다른 모든 비교는 다음과 같이 평가됩니다.UNKNOWN
아닌 FALSE
설명서에는 다음과 같은 내용이 추가되어 있습니다.
알 수 없음으로 평가되는 조건은 거의 FALSE처럼 작동합니다.예를 들어 WHERE 절에 UNKNOWN으로 평가되는 조건이 있는 SELECT 문은 행을 반환하지 않습니다.그러나 UNKNOWN으로 평가되는 조건은 UNKNOWN 조건 평가에 대한 추가 작업이 UNKNOWN으로 평가된다는 점에서 FALSE와 다릅니다.따라서 거짓은 참으로 평가되지만 알 수 없음은 알 수 없음으로 평가됩니다.
참조 테이블은 Oracle에서 제공합니다.
Condition Value of A Evaluation
----------------------------------------
a IS NULL 10 FALSE
a IS NOT NULL 10 TRUE
a IS NULL NULL TRUE
a IS NOT NULL NULL FALSE
a = NULL 10 UNKNOWN
a != NULL 10 UNKNOWN
a = NULL NULL UNKNOWN
a != NULL NULL UNKNOWN
a = 10 NULL UNKNOWN
a != 10 NULL UNKNOWN
또한 빈 문자열이 항상 NULL로 평가된다고 가정하면 PL/SQL을 작성해서는 안 된다는 것을 배웠습니다.
Oracle Database는 현재 길이가 0인 문자 값을 null로 처리합니다.그러나 이후 릴리스에서는 이러한 현상이 계속 적용되지 않을 수 있으므로 빈 문자열은 null과 동일하게 처리하지 않는 것이 좋습니다.
논리의 다른 분기를 추가하여 코드의 공백을 메우고 다음과 같은 작업이 수행되는지 살펴보겠습니다.
SQL> DECLARE
2 str1 varchar2(4000);
3 str2 varchar2(4000);
4 BEGIN
5 str1:='';
6 str2:='sdd';
7 IF(str1<>str2) THEN
8 dbms_output.put_line('The two strings is not equal');
9 ELSIF (str1=str2) THEN
10 dbms_output.put_line('The two strings are the same');
11 ELSE
12 dbms_output.put_line('Who knows?');
13 END IF;
14 END;
15 /
Who knows?
PL/SQL procedure successfully completed.
SQL>
그럼 이 두 줄은 같지도 않고 같지도 않은 건가요?
결론은 이렇습니다.Oracle은 빈 문자열을 NULL로 처리합니다.NULL과 다른 문자열을 비교하려고 하면 결과가 TRUE 또는 FALSE가 아닌 NULL입니다.다른 문자열도 NULL인 경우에도 마찬가지입니다.
사용하여 문자열을 비교합니다.=
그리고 아닌<>
이런 맥락에서 볼 때=
보다 더 합리적인 방식으로 작동하는 것 같습니다.<>
두 개의 빈(또는 NULL) 문자열이 동일하도록 지정했습니다.실제 구현은 PL/SQL boolean을 반환하지만 여기서 함수를 쉽게 시연할 수 있도록 pls_integer(0은 false, 1은 true)로 변경했습니다.
create or replace function is_equal(a in varchar2, b in varchar2)
return pls_integer as
begin
if a is null and b is null then
return 1;
end if;
if a = b then
return 1;
end if;
return 0;
end;
/
show errors
begin
/* Prints 0 */
dbms_output.put_line(is_equal('AAA', 'BBB'));
dbms_output.put_line(is_equal('AAA', null));
dbms_output.put_line(is_equal(null, 'BBB'));
dbms_output.put_line(is_equal('AAA', ''));
dbms_output.put_line(is_equal('', 'BBB'));
/* Prints 1 */
dbms_output.put_line(is_equal(null, null));
dbms_output.put_line(is_equal(null, ''));
dbms_output.put_line(is_equal('', ''));
dbms_output.put_line(is_equal('AAA', 'AAA'));
end;
/
"이두 중 때 이 두 이 같지 것을 라는 질문을 는 "이 변수들 중 하나가 null일 때 null일 때 null일 때 null일 때 null일 때 null일 때 null일 때 null일 때 null일 때 이 변수들을 어떻게 감지해야 요?"라는 에 들지 .라는 핵심 질문을 해결하기 위해, 저는 다음과 같은 접근 방식을 좋아하지 않습니다.nvl(my_column, 'some value that will never, ever, ever appear in the data and I can be absolutely sure of that')
항상 가치가 나타나지 않는다고 보장할 수는 없기 때문입니다.특히 NUMBES의 경우.
다음을 사용했습니다.
if (str1 is null) <> (str2 is null) or str1 <> str2 then
dbms_output.put_line('not equal');
end if;
例고:가 아닙니다. 저는 이 를 직접 곳에서는 본 때문에, 수 .저는 Oracle 마법사가 아닙니다. 제가 직접 생각해 낸 것이지만 다른 곳에서는 본 적이 없기 때문에 좋지 않은 이유가 있을 수 있습니다.그러나 APC에서 언급한 트랩을 피합니다. null을 다른 것과 비교하면 TRUE도 FALSE도 아닌 NULL이 제공됩니다. 왜하면 그조들 항은냐라는 절이 있기 입니다.(str1 is null)
항상 TRUE 또는 FALSE를 반환하며 null은 반환하지 않습니다.
(PL/SQL은 여기에 명시된 바와 같이 단락 평가를 수행합니다.)
이 텍스트 비교 목적으로 저장된 함수를 만들었습니다.
CREATE OR REPLACE FUNCTION TextCompare(vOperand1 IN VARCHAR2, vOperator IN VARCHAR2, vOperand2 IN VARCHAR2) RETURN NUMBER DETERMINISTIC AS
BEGIN
IF vOperator = '=' THEN
RETURN CASE WHEN vOperand1 = vOperand2 OR vOperand1 IS NULL AND vOperand2 IS NULL THEN 1 ELSE 0 END;
ELSIF vOperator = '<>' THEN
RETURN CASE WHEN vOperand1 <> vOperand2 OR (vOperand1 IS NULL) <> (vOperand2 IS NULL) THEN 1 ELSE 0 END;
ELSIF vOperator = '<=' THEN
RETURN CASE WHEN vOperand1 <= vOperand2 OR vOperand1 IS NULL THEN 1 ELSE 0 END;
ELSIF vOperator = '>=' THEN
RETURN CASE WHEN vOperand1 >= vOperand2 OR vOperand2 IS NULL THEN 1 ELSE 0 END;
ELSIF vOperator = '<' THEN
RETURN CASE WHEN vOperand1 < vOperand2 OR vOperand1 IS NULL AND vOperand2 IS NOT NULL THEN 1 ELSE 0 END;
ELSIF vOperator = '>' THEN
RETURN CASE WHEN vOperand1 > vOperand2 OR vOperand1 IS NOT NULL AND vOperand2 IS NULL THEN 1 ELSE 0 END;
ELSIF vOperator = 'LIKE' THEN
RETURN CASE WHEN vOperand1 LIKE vOperand2 OR vOperand1 IS NULL AND vOperand2 IS NULL THEN 1 ELSE 0 END;
ELSIF vOperator = 'NOT LIKE' THEN
RETURN CASE WHEN vOperand1 NOT LIKE vOperand2 OR (vOperand1 IS NULL) <> (vOperand2 IS NULL) THEN 1 ELSE 0 END;
ELSE
RAISE VALUE_ERROR;
END IF;
END;
예:
SELECT * FROM MyTable WHERE TextCompare(MyTable.a, '>=', MyTable.b) = 1;
행 str1:=';을 str1:=' ';으로 변경합니다.
"는 NULL로 처리되므로 두 문자열 모두 NULL로 확인해야 합니다.
기능:
CREATE OR REPLACE FUNCTION str_cmpr_fnc(str_val1_in IN VARCHAR2, str_val2_in IN VARCHAR2) RETURN VARCHAR2
AS
l_result VARCHAR2(50);
BEGIN
-- string comparison
CASE
WHEN str_val1_in IS NULL AND str_val2_in IS NULL THEN
l_result := 'Both Unknown';
WHEN str_val1_in IS NULL THEN
l_result := 'Str1 Unknown';
WHEN str_val2_in IS NULL THEN
l_result := 'Str2 Unknown';
ELSE
CASE
WHEN str_val1_in = str_val2_in THEN
l_result := 'Both are equel';
ELSE
l_result := 'Both strings are not equal';
END CASE;
END CASE;
-- return result
RETURN l_result;
EXCEPTION
WHEN OTHERS THEN
-- set serveroutput on to get the error information
DBMS_OUTPUT.put_line(SQLERRM||' ,'|| DBMS_UTILITY.FORMAT_ERROR_BACKTRACE);
-- return result
RETURN l_result;
END str_cmpr_fnc;
SQL 문:
SELECT str_cmpr_fnc('7', 'd') FROM DUAL;
첫 번째 질문으로:
출력이 꺼져 있어서 메시지가 출력되지 않은 것 같습니다.다음 명령을 사용하여 다시 켭니다.
set serveroutput on
exec dbms_output.enable(1000000);
두 번째 질문:
제 PLSQL은 녹슬어서 전체 스니펫을 드릴 수는 없지만 SQL 쿼리의 결과 집합과 CONCAT의 모든 문자열을 함께 루프해야 합니다.
언급URL : https://stackoverflow.com/questions/7286047/oracle-pl-sql-string-compare-issue
'programing' 카테고리의 다른 글
Oracle에서 선택한 행에서 행 번호를 가져오는 방법 (0) | 2023.07.07 |
---|---|
ggplot을 사용하여 플롯을 만들 때 hjust와 vjust는 무엇을 합니까? (0) | 2023.07.07 |
Windows 7에서 명령 프롬프트에서 Python 프로그램을 실행하는 방법은 무엇입니까? (0) | 2023.07.07 |
메모리 제한 초과로 인해 Firebase의 클라우드 기능이 중지되었습니다. (0) | 2023.07.07 |
MongoDB 집계 프레임워크를 사용하여 소수점 이하 2자리로 반올림 (0) | 2023.07.07 |