SQL(Oracle,MSSQL,Postgre)

[MS-SQL/ SQL Server] 자주 발생하는 에러 원인 및 해결방법 정리

Hero0309 2026. 8. 30. 17:34
반응형

[SQL Server]자주 발생하는 에러 코드별 원인과 즉시 해결 방법

MS SQL Server(T-SQL)로 쿼리를 작성하다 보면 구문 오류부터 데이터 변환 오류, 제약 조건 위반까지 다양한 에러를 만나게 됩니다.

오라클과 달리 SQL Server는 ORA- 형태가 아닌 메시지 번호(Msg) 로 오류를 구분하며, 번호만 알면 원인 범위를 상당히 좁힐 수 있습니다. 이번 글에서는 실무에서 가장 빈번하게 마주치는 SQL Server 오류를 유형별로 정리하고, 즉시 적용 가능한 해결 방법을 코드와 함께 정리했습니다.

(예제는 SQL Server 2016 이상 기준이며, 2019 이상에서만 동작하는 항목은 별도로 표기했습니다.)


1. 먼저 알아야 할 것: SQL Server 에러 메시지 읽는 법

SQL Server의 오류는 항상 아래와 같은 형태로 출력됩니다. 이 구조만 이해해도 원인 파악 속도가 크게 달라집니다.

Msg 8120, Level 16, State 1, Line 3
Column 'dbo.employees.job_id' is invalid in the select list because it is not
contained in either an aggregate function or the GROUP BY clause.
항목 의미
Msg (메시지 번호) 오류의 고유 번호. 검색과 예외 처리(ERROR_NUMBER())의 기준이 됩니다.
Level (심각도) 오류의 등급. 아래 표 참고.
State (상태) 같은 오류 번호가 여러 지점에서 발생할 때 이를 구분하는 내부 코드.
Line (줄 번호) 오류가 발생한 줄. GO로 구분되는 배치(batch) 단위로 세어지므로, 스크립트 전체 줄 번호와 다를 수 있습니다.

심각도(Severity Level)별 대응

수준 성격 대응 방법
0 ~ 10 정보성 메시지 (오류 아님) 확인만 하면 됨
11 ~ 16 사용자가 수정 가능한 오류 쿼리나 데이터를 수정하면 해결 — 이 글에서 다루는 대부분이 여기에 해당
17 ~ 19 리소스 부족, 내부 오류 DBA 확인 필요 (메모리, 디스크, 로그 공간 등)
20 ~ 24 치명적 오류 연결이 강제 종료됨. 하드웨어·DB 손상 점검 필요

Tip: 심각도 11~16 오류는 TRY...CATCH로 잡을 수 있지만, 20 이상의 치명적 오류나 컴파일 단계 오류는 잡히지 않습니다. (자세한 내용은 6-2 참고)


2. 구문 및 객체 참조 오류

2-1. Msg 156: Incorrect syntax near the keyword 'xxx'

예약어(Reserved Keyword)를 식별자로 사용했을 때 가장 많이 발생합니다.

잘못된 예시 (Error 발생):

-- order, user, key, desc, percent 등은 모두 T-SQL 예약어
SELECT order, user, desc
FROM dbo.sales_order;

올바른 예시 (Fixed):

-- 대괄호로 감싸면 예약어도 식별자로 인식됨
SELECT [order], [user], [desc]
FROM dbo.sales_order;

근본 해결책: 대괄호는 임시방편입니다. 신규 설계 시에는 order_no, user_id, description처럼 예약어를 피한 명명 규칙을 사용하는 편이 유지보수에 훨씬 유리합니다.

이 밖에 SELECT 절 컬럼 사이의 쉼표 누락, BEGIN에 대응하는 END 누락, 문자열 내 홑따옴표 이스케이프('It''s') 누락도 Msg 156/102의 흔한 원인입니다.

2-2. Msg 102: Incorrect syntax near 'xxx' — 타 DBMS 문법 혼용

MySQL의 LIMIT이나 오라클의 ROWNUM을 그대로 옮겨 쓰면 발생합니다. SQL Server는 두 구문 모두 지원하지 않습니다.

잘못된 예시 (Error 발생):

SELECT emp_name, salary
FROM dbo.employees
ORDER BY salary DESC
LIMIT 10;

올바른 예시 (Fixed):

-- 방법 1: TOP (모든 버전)
SELECT TOP (10) emp_name, salary
FROM dbo.employees
ORDER BY salary DESC;

-- 방법 2: OFFSET ... FETCH (SQL Server 2012 이상, 페이징에 적합)
SELECT emp_name, salary
FROM dbo.employees
ORDER BY salary DESC
OFFSET 10 ROWS FETCH NEXT 10 ROWS ONLY;

OFFSET ... FETCH는 반드시 ORDER BY와 함께 사용해야 하며, ORDER BY 없이 쓰면 구문 오류가 발생합니다.

2-3. Msg 1033: 서브쿼리·뷰 안의 ORDER BY

The ORDER BY clause is invalid in views, inline functions, derived tables, subqueries, and common table expressions, unless TOP, OFFSET or FOR XML is also specified.

잘못된 예시 (Error 발생):

SELECT *
FROM (
    SELECT employee_id, salary
    FROM dbo.employees
    ORDER BY salary DESC   -- 파생 테이블 내부에서는 정렬 불가
) AS t;

올바른 예시 (Fixed):

-- 정렬은 최종 결과 집합에서 수행
SELECT employee_id, salary
FROM (
    SELECT employee_id, salary
    FROM dbo.employees
) AS t
ORDER BY salary DESC;

주의: TOP (100) PERCENT를 붙여 에러를 회피하는 방법이 널리 알려져 있지만, 옵티마이저가 해당 정렬을 제거할 수 있어 순서가 보장되지 않습니다. 정렬은 항상 가장 바깥쪽 쿼리에서 수행하세요. 내부 정렬이 꼭 필요하다면 ROW_NUMBER() 같은 순위 함수를 사용하는 것이 정석입니다.

2-4. Msg 4104: The multi-part identifier "x.y" could not be bound

테이블 별칭이 잘못되었거나 정의되지 않은 경우 발생합니다. 특히 테이블에 별칭을 부여하면 원래 테이블명으로는 더 이상 참조할 수 없다는 점을 놓치기 쉽습니다.

잘못된 예시 (Error 발생):

SELECT e.emp_name, d.dept_name
FROM dbo.employees AS e
JOIN dbo.departments AS dept
  ON e.department_id = dept.department_id;   -- 별칭은 dept인데 SELECT에서는 d로 참조

올바른 예시 (Fixed):

SELECT e.emp_name, d.dept_name
FROM dbo.employees AS e
JOIN dbo.departments AS d
  ON e.department_id = d.department_id;

주요 발생 원인은 다음과 같습니다.

  • SELECT/WHERE 절의 별칭과 FROM 절의 별칭이 불일치
  • 별칭을 부여한 뒤 dbo.employees.emp_name처럼 전체 테이블명으로 참조
  • UPDATE 문에서 별칭 사용 위치 오류 (UPDATE e SET ... FROM dbo.employees AS e 형태로 작성해야 함)
  • 컬럼명 오타 또는 해당 테이블에 존재하지 않는 컬럼 참조

2-5. Msg 208: Invalid object name 'xxx'

객체 자체를 찾지 못하는 오류로, 원인이 다양합니다.

  • 데이터베이스 컨텍스트 불일치 — SSMS 상단의 DB 선택이 다른 경우. USE [DB명];으로 명시
  • 스키마 누락 — 기본 스키마가 dbo가 아닌 계정에서 SELECT * FROM employees 실행. 항상 dbo.employees처럼 스키마를 명시
  • 임시 테이블 범위 문제 — 로컬 임시 테이블(#temp)은 생성한 세션·배치 내에서만 유효. 다른 세션에서 접근하려면 전역 임시 테이블(##temp)이 필요
  • 링크드 서버 참조 오류 — 4단계 명명([서버].[DB].[스키마].[테이블]) 중 일부 누락
  • 개체 미배포 — 개발 서버에만 존재하고 운영 서버에는 배포되지 않은 경우

존재 여부 확인 쿼리:

SELECT OBJECT_ID('dbo.employees', 'U') AS object_id;   -- NULL이면 현재 DB에 없음

SELECT s.name AS schema_name, t.name AS table_name
FROM sys.tables AS t
JOIN sys.schemas AS s ON t.schema_id = s.schema_id
WHERE t.name LIKE '%employee%';

3. 집계 및 GROUP BY 오류

3-1. Msg 8120 / 8121: Column 'x' is invalid in the select list...

집계 함수를 사용할 때 GROUP BY에 없는 일반 컬럼을 조회하면 발생합니다. 오라클의 ORA-00979에 대응하는 오류이며, SQL Server에는 MySQL의 ONLY_FULL_GROUP_BY처럼 이 검사를 완화하는 옵션이 없습니다. 항상 표준 규칙을 따라야 합니다.

  • Msg 8120SELECT 절에서 위반한 경우
  • Msg 8121HAVING 절에서 위반한 경우

잘못된 예시 (Error 발생):

SELECT department_id, job_id, AVG(salary) AS avg_salary
FROM dbo.employees
GROUP BY department_id;

해결 1 — 그룹 기준에 추가:

SELECT department_id, job_id, AVG(salary) AS avg_salary
FROM dbo.employees
GROUP BY department_id, job_id;

주의: 에러는 사라지지만 집계 단위가 "부서별"에서 "부서+직무별"로 바뀝니다. 원하는 집계 단위인지 먼저 확인하세요.

해결 2 — 집계 함수로 축약 (부서별 단위 유지):

SELECT department_id,
       MAX(job_id) AS sample_job_id,
       AVG(salary) AS avg_salary
FROM dbo.employees
GROUP BY department_id;

해결 3 — 윈도우 함수 사용 (원본 행을 모두 유지):

SELECT department_id,
       job_id,
       salary,
       AVG(salary) OVER (PARTITION BY department_id) AS dept_avg_salary
FROM dbo.employees;

4. 데이터 변환 및 연산 오류

4-1. Msg 245: Conversion failed when converting the varchar value 'xxx' to data type int

암시적 형 변환(Implicit Conversion) 때문에 발생합니다. SQL Server는 서로 다른 데이터 형식을 비교할 때 우선순위가 낮은 쪽을 높은 쪽으로 변환하는데, intvarchar보다 우선순위가 높기 때문에 문자열 컬럼 전체가 숫자로 변환되면서 실패합니다.

잘못된 예시 (Error 발생):

-- product_code는 VARCHAR(20). 'A-1001' 같은 값이 있으면 변환 실패
SELECT * FROM dbo.products WHERE product_code = 1001;

올바른 예시 (Fixed):

-- 컬럼과 동일한 데이터 형식으로 비교
SELECT * FROM dbo.products WHERE product_code = '1001';

성능 관점의 중요 포인트: 이 오류가 발생하지 않더라도, 컬럼 쪽에 암시적 변환이 걸리면 인덱스를 타지 못하고 테이블 스캔이 발생합니다. 조회 조건의 데이터 형식은 항상 컬럼과 일치시키는 것이 원칙입니다.

문자열을 숫자로 변환해야 할 때 (SQL Server 2012 이상):

-- 변환 실패 시 에러 대신 NULL을 반환
SELECT product_code,
       TRY_CAST(product_code AS INT) AS code_num
FROM dbo.products
WHERE TRY_CAST(product_code AS INT) > 1000;

ISNUMERIC()은 신뢰하지 마세요. ISNUMERIC('$'), ISNUMERIC('1e5'), ISNUMERIC('1,000')은 모두 1을 반환하지만 INT 변환은 실패합니다. 또한 WHERE ISNUMERIC(col) = 1 AND CAST(col AS INT) > 10 형태는 조건 평가 순서가 보장되지 않아 여전히 오류가 날 수 있습니다. TRY_CAST / TRY_CONVERT를 사용하세요.

4-2. Msg 8115: Arithmetic overflow error converting expression to data type int

INT의 최대값(2,147,483,647)을 초과할 때 발생합니다. SUM(INT 컬럼)의 결과 형식도 INT 라는 점이 함정입니다.

잘못된 예시 (Error 발생):

-- quantity가 INT일 때, 누적 합계가 21억을 넘으면 오류
SELECT SUM(quantity) AS total_qty
FROM dbo.order_detail;

올바른 예시 (Fixed):

-- 집계 전에 BIGINT로 변환
SELECT SUM(CAST(quantity AS BIGINT)) AS total_qty
FROM dbo.order_detail;

곱셈에서도 동일합니다. SELECT 100000 * 100000; 은 오류가 나지만, SELECT CAST(100000 AS BIGINT) * 100000; 은 정상 동작합니다.

4-3. Msg 8134: Divide by zero error encountered

잘못된 예시 (Error 발생):

SELECT product_id, sales_amount / target_amount AS achievement_rate
FROM dbo.sales_summary;

올바른 예시 (Fixed):

-- NULLIF로 분모가 0이면 NULL로 치환 → 결과도 NULL
SELECT product_id,
       sales_amount / NULLIF(target_amount, 0) AS achievement_rate
FROM dbo.sales_summary;

-- 0으로 표시하고 싶다면 ISNULL로 한 번 더 감싸기
SELECT product_id,
       ISNULL(sales_amount / NULLIF(target_amount, 0), 0) AS achievement_rate
FROM dbo.sales_summary;

SET ARITHABORT OFF / SET ANSI_WARNINGS OFF로도 오류를 억제할 수 있지만, 인덱싱된 뷰나 계산 열 사용에 제약이 생기고 실행 계획에도 영향을 주므로 권장하지 않습니다.

4-4. Msg 8152 / 2628: String or binary data would be truncated

정의된 길이보다 긴 문자열을 저장하려 할 때 발생합니다.

-- emp_name이 NVARCHAR(10)인 테이블
INSERT INTO dbo.employees (emp_name) VALUES (N'홍길동홍길동홍길동홍길동');

과거 버전의 Msg 8152는 어느 컬럼에서 문제가 생겼는지 알려주지 않아 원인 파악이 어려웠습니다. SQL Server 2019부터는 기본적으로 Msg 2628이 출력되어 테이블명·컬럼명·잘린 값까지 함께 표시됩니다. (SQL Server 2016 SP2 / 2017 환경에서는 추적 플래그 460을 활성화하면 동일한 메시지를 볼 수 있습니다.)

원인 컬럼을 찾는 방법:

-- 1. 컬럼 정의 길이 확인
SELECT c.name AS column_name, t.name AS data_type, c.max_length
FROM sys.columns AS c
JOIN sys.types  AS t ON c.user_type_id = t.user_type_id
WHERE c.object_id = OBJECT_ID('dbo.employees');

-- 2. 원본 데이터에서 초과 행 찾기
SELECT emp_name, LEN(emp_name) AS char_len, DATALENGTH(emp_name) AS byte_len
FROM dbo.staging_employees
WHERE LEN(emp_name) > 10;

LENDATALENGTH 구분: LEN문자 수(후행 공백 제외), DATALENGTH바이트 수를 반환합니다. NVARCHAR는 한 문자당 2바이트, VARCHAR에 한글을 저장하면 한 글자당 2바이트를 차지합니다. VARCHAR(10) 컬럼에 한글은 5글자까지만 들어간다는 점을 놓치는 경우가 많습니다.


5. 제약 조건 및 동시성 오류

5-1. Msg 2627 / 2601: 키 중복 위반

  • Msg 2627 — PRIMARY KEY 또는 UNIQUE 제약 조건 위반
  • Msg 2601 — UNIQUE 인덱스 위반

두 오류 모두 중복된 키 값을 메시지에 함께 출력하므로, 어떤 값이 문제인지 바로 확인할 수 있습니다.

중복을 피하는 안전한 INSERT:

-- 존재하지 않을 때만 삽입
INSERT INTO dbo.employees (employee_id, emp_name)
SELECT s.employee_id, s.emp_name
FROM dbo.staging_employees AS s
WHERE NOT EXISTS (
    SELECT 1
    FROM dbo.employees AS e
    WHERE e.employee_id = s.employee_id
);

동시 실행이 잦은 환경이라면 WHERE NOT EXISTS만으로는 경합 구간이 남을 수 있으므로, 트랜잭션과 적절한 잠금 힌트를 함께 검토하거나 오류 2627을 TRY...CATCH에서 처리하는 방식을 병행하는 것이 안전합니다.

5-2. Msg 547: FOREIGN KEY 제약 조건 충돌

메시지에 어떤 동작에서 충돌했는지가 함께 표시되므로 방향을 먼저 확인해야 합니다.

  • INSERT/UPDATE 시 충돌 — 참조하려는 부모 행이 존재하지 않는 경우 → 부모 테이블에 먼저 데이터를 입력
  • DELETE 시 충돌 — 삭제하려는 행을 참조하는 자식 행이 남아 있는 경우 → 자식 행을 먼저 삭제하거나 논리 삭제 사용
-- 어떤 자식 행이 막고 있는지 확인
SELECT * FROM dbo.order_detail WHERE order_id = 1001;

-- 제약 조건 정의 확인
SELECT fk.name AS fk_name,
       OBJECT_NAME(fk.parent_object_id)     AS child_table,
       OBJECT_NAME(fk.referenced_object_id) AS parent_table,
       fk.delete_referential_action_desc
FROM sys.foreign_keys AS fk
WHERE fk.referenced_object_id = OBJECT_ID('dbo.orders');

ON DELETE CASCADE는 편리하지만, 대량 삭제 시 연쇄적으로 다수의 테이블이 잠기고 예상치 못한 데이터 손실로 이어질 수 있어 운영 환경에서는 신중히 적용해야 합니다.

5-3. Msg 512: Subquery returned more than 1 value

단일 값을 기대하는 위치(스칼라 서브쿼리, = 비교 등)에 여러 행이 반환될 때 발생합니다. 대부분은 쿼리 문제가 아니라 데이터에 중복이 있다는 신호이므로, 먼저 중복 여부를 확인하는 것이 중요합니다.

잘못된 예시 (Error 발생):

SELECT e.emp_name,
       (SELECT d.dept_name
        FROM dbo.departments AS d
        WHERE d.department_id = e.department_id) AS dept_name
FROM dbo.employees AS e;

중복 확인:

SELECT department_id, COUNT(*) AS cnt
FROM dbo.departments
GROUP BY department_id
HAVING COUNT(*) > 1;

해결 방법:

-- 방법 1: JOIN으로 전환 (권장)
SELECT e.emp_name, d.dept_name
FROM dbo.employees AS e
LEFT JOIN dbo.departments AS d
       ON d.department_id = e.department_id;

-- 방법 2: 여러 건 중 하나만 필요한 경우 OUTER APPLY + TOP
SELECT e.emp_name, d.dept_name
FROM dbo.employees AS e
OUTER APPLY (
    SELECT TOP (1) d2.dept_name
    FROM dbo.departments AS d2
    WHERE d2.department_id = e.department_id
    ORDER BY d2.updated_at DESC
) AS d;

-- 방법 3: 존재 여부만 확인하면 되는 경우 IN / EXISTS
SELECT e.emp_name
FROM dbo.employees AS e
WHERE e.department_id IN (SELECT department_id FROM dbo.departments);

5-4. Msg 1205: 교착 상태(Deadlock)

Transaction (Process ID xx) was deadlocked on lock resources with another process and has been chosen as the deadlock victim. Rerun the transaction.

두 개 이상의 세션이 서로가 점유한 자원을 기다리며 무한 대기에 빠지면, SQL Server가 한쪽을 희생자(victim) 로 선정해 강제 롤백합니다.

예방 및 완화 방법

  1. 객체 접근 순서 통일 — 모든 프로시저에서 테이블을 동일한 순서로 접근하면 교착 발생 확률이 크게 줄어듭니다.
  2. 트랜잭션 구간 최소화 — 트랜잭션 안에서 사용자 입력 대기, 외부 API 호출, 불필요한 조회를 하지 않습니다.
  3. 인덱스 최적화 — 적절한 인덱스가 없으면 스캔 범위가 넓어지고 잠금 대상도 함께 늘어납니다.
  4. 재시도 로직 구현 — 교착은 완전히 없앨 수 없으므로 애플리케이션 또는 프로시저에 재시도를 넣는 것이 현실적입니다.
  5. READ COMMITTED SNAPSHOT 검토 — 읽기와 쓰기 간 차단을 줄일 수 있으나, tempdb 사용량이 늘어나므로 사전 검증이 필요합니다.

재시도 패턴 예시:

DECLARE @retry INT = 0;

WHILE @retry < 3
BEGIN
    BEGIN TRY
        BEGIN TRANSACTION;

        -- 실제 업무 로직
        UPDATE dbo.inventory
           SET qty = qty - 1
         WHERE item_id = 'A001';

        COMMIT TRANSACTION;
        BREAK;   -- 성공 시 반복 종료
    END TRY
    BEGIN CATCH
        IF XACT_STATE() <> 0 ROLLBACK TRANSACTION;

        IF ERROR_NUMBER() = 1205 AND @retry < 2
        BEGIN
            SET @retry += 1;
            WAITFOR DELAY '00:00:01';   -- 1초 대기 후 재시도
        END
        ELSE
        BEGIN
            THROW;   -- 교착이 아니거나 재시도 초과 시 오류 전파
        END
    END CATCH
END

교착 상태 이력 확인 (system_health 세션 활용):

SELECT XEvent.query('.') AS deadlock_graph
FROM (
    SELECT CAST(target_data AS XML) AS TargetData
    FROM sys.dm_xe_session_targets AS st
    JOIN sys.dm_xe_sessions AS s ON s.address = st.event_session_address
    WHERE s.name = 'system_health'
      AND st.target_name = 'ring_buffer'
) AS Data
CROSS APPLY TargetData.nodes('RingBufferTarget/event[@name="xml_deadlock_report"]') AS XEventData(XEvent);

6. 오류를 줄이는 실무 팁

6-1. 변환은 TRY_ 계열 함수로

SQL Server 2012부터 제공되는 아래 함수들은 변환 실패 시 오류 대신 NULL을 반환합니다. 외부 데이터 적재나 정합성 검증 쿼리에서 특히 유용합니다.

함수 용도
TRY_CAST(값 AS 형식) 표준 형 변환
TRY_CONVERT(형식, 값, 스타일) 날짜 스타일 코드 등 변환 옵션이 필요할 때
TRY_PARSE(값 AS 형식 USING '문화권') '2026년 8월 30일' 같은 문화권 의존 문자열 파싱 (비용이 높으므로 남용 금지)

6-2. TRY...CATCH로 예외를 명시적으로 처리

BEGIN TRY
    -- 오류가 발생할 수 있는 구문
    INSERT INTO dbo.employees (employee_id, emp_name) VALUES (1, N'홍길동');
END TRY
BEGIN CATCH
    SELECT ERROR_NUMBER()    AS error_number,     -- Msg 번호
           ERROR_SEVERITY()  AS error_severity,   -- Level
           ERROR_STATE()     AS error_state,      -- State
           ERROR_LINE()      AS error_line,       -- 줄 번호
           ERROR_PROCEDURE() AS error_procedure,  -- 프로시저명
           ERROR_MESSAGE()   AS error_message;

    THROW;   -- 원본 오류를 그대로 상위로 전파 (SQL Server 2012 이상)
END CATCH

TRY...CATCH가 잡지 못하는 오류가 있습니다.

  • 구문 오류(Msg 102, 156 등) — 배치 컴파일 단계에서 실패하므로 TRY 블록에 도달하지 못합니다.
  • 같은 배치 내의 개체 이름 확인 오류(Msg 208) — 지연 해석되지 않으면 컴파일 단계에서 실패합니다. 동적 SQL(sp_executesql)로 분리하면 잡을 수 있습니다.
  • 심각도 20 이상의 치명적 오류 — 연결 자체가 종료됩니다.

6-3. 트랜잭션에는 SET XACT_ABORT ON

XACT_ABORTOFF(기본값)인 상태에서는 일부 런타임 오류 발생 시에도 트랜잭션이 그대로 열려 있어, 잠금이 유지되거나 일부만 반영되는 위험이 있습니다. 저장 프로시저 상단에 아래 구문을 두는 것을 권장합니다.

SET NOCOUNT ON;      -- 불필요한 영향 행 수 메시지 억제 (네트워크 부하 감소)
SET XACT_ABORT ON;   -- 런타임 오류 발생 시 트랜잭션 전체 자동 롤백

6-4. 오라클 ↔ SQL Server 구문 대응표

두 DBMS를 함께 다루는 환경에서 문법을 혼용해 발생하는 오류가 많습니다.

기능 Oracle SQL Server
상위 N건 조회 ROWNUM, FETCH FIRST n ROWS ONLY TOP (n), OFFSET ... FETCH NEXT
NULL 치환 NVL(a, b) ISNULL(a, b) / COALESCE(a, b)
문자열 결합 a || b, CONCAT a + b, CONCAT
현재 시각 SYSDATE GETDATE() / SYSDATETIME()
형 변환 TO_CHAR, TO_DATE, TO_NUMBER CONVERT, CAST, FORMAT
조건 분기 DECODE, CASE CASE, IIF
문자열 자르기 SUBSTR SUBSTRING
더미 테이블 DUAL 필요 불필요 (SELECT 1;)
테이블 별칭 AS 사용 불가 사용 가능
빈 문자열 ''NULL로 취급 ''NULL은 서로 다름

7. 빠른 참조: 에러 코드 요약

Msg 메시지 요약 주요 원인 대표 해결책
102 / 156 Incorrect syntax near 예약어 사용, 타 DBMS 문법 대괄호 [ ], TOP/OFFSET FETCH
208 Invalid object name DB·스키마 불일치, 미배포 USE 명시, dbo. 접두어
245 Conversion failed 암시적 형 변환 실패 형식 일치, TRY_CAST
512 Subquery returned more than 1 value 데이터 중복 JOIN, OUTER APPLY + TOP (1)
547 Constraint conflict FK 부모 부재 / 자식 잔존 입력·삭제 순서 조정
1033 ORDER BY invalid in subqueries 파생 테이블 내부 정렬 최상위 쿼리에서 정렬
1205 Deadlock victim 자원 접근 순서 불일치 접근 순서 통일, 재시도 로직
2601 / 2627 Duplicate key 키 중복 NOT EXISTS, MERGE
4104 Multi-part identifier could not be bound 별칭 오류 별칭 일관성 확인
8115 Arithmetic overflow INT 범위 초과 CAST(... AS BIGINT)
8120 / 8121 Invalid in the select/having list GROUP BY 누락 그룹 기준 추가 또는 집계·윈도우 함수
8134 Divide by zero 분모 0 NULLIF(분모, 0)
8152 / 2628 Data would be truncated 길이 초과 길이 확인, 컬럼 확장

마치며

SQL Server 오류 해결의 첫걸음은 메시지 번호를 확인하는 것입니다. 번호 하나만으로도 구문 문제인지, 데이터 문제인지, 제약 조건이나 동시성 문제인지 즉시 구분할 수 있습니다.

특히 실무에서는 TRY_CAST로 변환 오류를, NULLIF로 0 나눗셈을, SET XACT_ABORT ON으로 트랜잭션 오류를 사전에 차단하는 습관만 들여도 장애 대응 시간이 크게 줄어듭니다. 위 참조표를 북마크해 두고 오류 발생 시 빠르게 대조해 보시기 바랍니다.

반응형