Oracle ORA-01700 오류 원인과 해결 방법 완벽 가이드

ORA-01700
2026년 07월 26일 | DBMS Error 가이드

이 글에서 다루는 내용

ORA-01700 에러의 원인 분석, 해결 SQL, 예방 방법을 실무 관점에서 정리합니다.

ORA-01700 duplicate username in list 는?

ORA-01700 에러는 Oracle에서 GRANT 문을 사용하여 권한을 부여할 때 대상 사용자 목록에 동일한 사용자명이 두 번 이상 중복으로 지정되었을 때 발생하는 에러입니다. Oracle 데이터베이스는 하나의 GRANT 문에서 동일한 사용자에게 동일한 권한을 중복으로 부여하는 것을 허용하지 않으며, 이를 감지하는 즉시 해당 에러를 발생시킵니다. 주로 대규모 권한 관리 작업이나 자동화 스크립트에서 사용자 목록을 관리할 때 실수로 중복 항목이 포함되는 경우에 자주 발생합니다.


주요 발생 원인

1. GRANT 문에서 동일 사용자명 중복 기재

가장 흔한 원인으로, GRANT 문의 사용자 목록에 동일한 사용자명을 실수로 두 번 이상 입력하는 경우입니다. 특히 여러 명의 사용자에게 권한을 한 번에 부여하는 긴 스크립트 작업 시, 수작업으로 편집하다가 복사-붙여넣기 실수로 인해 발생하는 경우가 많습니다.

-- 에러 발생 예시: SCOTT이 두 번 등장
GRANT SELECT ON hr.employees TO scott, james, scott;
-- ORA-01700: duplicate username in list

2. 동적 SQL 또는 자동화 스크립트에서의 중복 생성

PL/SQL이나 셸 스크립트를 이용한 자동화된 권한 부여 과정에서 사용자 목록을 동적으로 생성할 때 중복 제거 로직이 없는 경우 발생합니다. 여러 소스에서 사용자 목록을 가져와 합치는 과정에서 중복 항목이 포함되는 경우가 특히 많으며, 이는 운영 환경에서 예기치 않은 장애를 일으킬 수 있습니다.

-- 잘못된 동적 SQL 예시
DECLARE
  v_sql VARCHAR2(1000);
BEGIN
  -- 여러 쿼리에서 합쳐진 사용자 목록에 중복이 포함될 수 있음
  v_sql := 'GRANT SELECT ON hr.employees TO ' ||
           'user_a, user_b, user_a';  -- user_a 중복!
  EXECUTE IMMEDIATE v_sql;
END;
/
-- ORA-01700: duplicate username in list

3. 대소문자 혼용으로 인한 논리적 중복

Oracle에서 일반적으로 사용자명은 대소문자를 구별하지 않지만(따옴표 없는 경우), 스크립트 작성자가 대소문자가 다르면 다른 사용자라고 오인하여 동일 사용자를 다르게 표기하는 경우가 발생합니다. 실제로 Oracle 내부적으로는 동일한 사용자로 처리되어 ORA-01700 에러가 발생합니다.

-- 대소문자 혼용으로 인한 중복 예시
GRANT SELECT ON hr.departments TO Scott, SCOTT, james;
-- Oracle은 SCOTT과 Scott을 동일 사용자로 처리
-- ORA-01700: duplicate username in list

해결 방법

원인 1 해결: 중복 사용자명 직접 제거

GRANT 문에서 중복된 사용자명을 직접 찾아 제거하는 것이 가장 직접적인 해결 방법입니다.

-- 수정 전 (에러 발생)
GRANT SELECT ON hr.employees TO scott, james, scott;

-- 수정 후 (중복 제거)
GRANT SELECT ON hr.employees TO scott, james;

-- 또는 개별 GRANT 문으로 분리
GRANT SELECT ON hr.employees TO scott;
GRANT SELECT ON hr.employees TO james;

원인 2 해결: 동적 SQL에서 중복 제거 로직 추가

자동화 스크립트에서는 사용자 목록을 처리하기 전에 반드시 중복을 제거하는 로직을 추가해야 합니다.

-- 안전한 동적 권한 부여 PL/SQL 예시
DECLARE
  TYPE t_users IS TABLE OF VARCHAR2(30);
  v_users  t_users := t_users('USER_A', 'USER_B', 'USER_A', 'USER_C');
  v_unique t_users := t_users();
  v_found  BOOLEAN;
  v_sql    VARCHAR2(4000);
  v_list   VARCHAR2(4000);
BEGIN
  -- 중복 제거 로직
  FOR i IN 1 .. v_users.COUNT LOOP
    v_found := FALSE;
    FOR j IN 1 .. v_unique.COUNT LOOP
      IF v_unique(j) = UPPER(v_users(i)) THEN
        v_found := TRUE;
        EXIT;
      END IF;
    END LOOP;
    IF NOT v_found THEN
      v_unique.EXTEND;
      v_unique(v_unique.COUNT) := UPPER(v_users(i));
    END IF;
  END LOOP;

  -- 중복 제거된 목록으로 GRANT 수행
  FOR i IN 1 .. v_unique.COUNT LOOP
    v_sql := 'GRANT SELECT ON hr.employees TO ' || v_unique(i);
    EXECUTE IMMEDIATE v_sql;
    DBMS_OUTPUT.PUT_LINE('Granted to: ' || v_unique(i));
  END LOOP;
END;
/

또한 사전에 딕셔너리 뷰를 활용하여 현재 권한 현황을 확인하고 중복 부여를 사전에 방지할 수 있습니다.

-- 특정 객체에 대해 이미 권한이 부여된 사용자 목록 확인
SELECT GRANTEE, PRIVILEGE, GRANT_OPTION
FROM   DBA_TAB_PRIVS
WHERE  TABLE_NAME = 'EMPLOYEES'
AND    OWNER      = 'HR'
ORDER BY GRANTEE;

-- 시스템 권한이 부여된 사용자 목록 확인
SELECT GRANTEE, PRIVILEGE
FROM   DBA_SYS_PRIVS
WHERE  PRIVILEGE = 'CREATE SESSION'
ORDER BY GRANTEE;

원인 3 해결: 사용자명 대소문자 통일

스크립트 작성 시 사용자명을 항상 UPPER() 함수 또는 대문자로 통일하여 처리합니다.

-- 사용자명 대문자 통일 후 GRANT
GRANT SELECT ON hr.departments TO SCOTT, JAMES;

-- PL/SQL에서 사용자명 정규화
DECLARE
  v_username VARCHAR2(30) := 'scott';  -- 소문자 입력
BEGIN
  EXECUTE IMMEDIATE 
    'GRANT SELECT ON hr.departments TO ' || UPPER(v_username);
  DBMS_OUTPUT.PUT_LINE('권한 부여 완료: ' || UPPER(v_username));
END;
/

-- DBA_USERS에서 정확한 사용자명 확인
SELECT USERNAME FROM DBA_USERS
WHERE  USERNAME LIKE '%SCOTT%'
ORDER BY USERNAME;

예방 방법

Best Practice 1: 권한 부여 전 사전 검증 스크립트 운영

권한 부여 스크립트를 실행하기 전에 반드시 대상 사용자 목록에 중복이 없는지 검증하는 사전 점검 단계를 도입하세요. 아래와 같이 SQL을 활용하여 현재 권한 현황과 대상 사용자 목록을 교차 확인하는 프로세스를 표준화하면 실수를 크게 줄일 수 있습니다.

-- 권한 부여 대상 사용자 목록에서 중복 확인 쿼리
-- (권한 부여 전 사전 점검용)
WITH target_users AS (
  SELECT 'SCOTT'  AS username FROM DUAL UNION ALL
  SELECT 'JAMES'  AS username FROM DUAL UNION ALL
  SELECT 'SCOTT'  AS username FROM DUAL  -- 중복!
)
SELECT username,
       COUNT(*) AS cnt
FROM   target_users
GROUP BY username
HAVING COUNT(*) > 1;
-- 위 쿼리 결과가 행을 반환하면 중복이 존재하는 것이므로 GRANT 실행 금지

Best Practice 2: 개별 GRANT 문 사용 및 예외 처리 로직 구현

한 번에 여러 사용자에게 권한을 부여하는 방식 대신, 사용자별 개별 GRANT 문을 사용하고 PL/SQL의 예외 처리를 함께 구현하면 에러 발생 시에도 나머지 작업이 중단되지 않습니다. 이 방식은 감사(Audit) 로그 기록과 롤백 처리를 명확하게 할 수 있어 대규모 권한 관리 작업에 특히 권장됩니다.

-- 개별 GRANT + 예외 처리 패턴
DECLARE
  TYPE t_users IS TABLE OF VARCHAR2(30);
  v_users t_users := t_users('SCOTT', 'JAMES', 'ADAMS');
BEGIN
  FOR i IN 1 .. v_users.COUNT LOOP
    BEGIN
      EXECUTE IMMEDIATE 
        'GRANT SELECT ON hr.employees TO ' || v_users(i);
      DBMS_OUTPUT.PUT_LINE('[SUCCESS] Granted to ' || v_users(i));
    EXCEPTION
      WHEN OTHERS THEN
        DBMS_OUTPUT.PUT_LINE('[ERROR] ' || v_users(i) || 
                             ': ' || SQLERRM);
        -- 에러가 발생해도 다음 사용자 처리 계속
    END;
  END LOOP;
END;
/

관련 에러

  • ORA-01917: user or role 'string' does not exist — GRANT 대상 사용자 또는 롤이 데이터베이스에 존재하지 않을 때 발생하며, ORA-01700과 함께 GRANT 문 작성 오류 시 자주 마주칩니다.
  • ORA-01919: role 'string' does not exist — 존재하지 않는 롤에 권한을 부여하려 할 때 발생합니다.
  • ORA-01924: role 'string' not granted or does not exist — 롤 관련 권한 부여 오류로, 권한 관리 작업 중 함께 나타날 수 있습니다.
  • ORA-00990: missing or invalid privilege — 유효하지 않은 권한을 GRANT하려 할 때 발생하며, 잘못된 GRANT 문 작성 시 ORA-01700과 비슷한 맥락에서 발생합니다.

DBMS 에러 코드 시리즈

주요 DBMS error code를 정리하는 시리즈입니다.
블로그 홈에서 다른 에러도 확인하세요.

본 포스트는 AI가 생성한 기술 가이드입니다. 운영 환경 적용 전 충분한 검토를 권장합니다.

댓글 남기기