파일 업로드
  1. base64hub
  2. 코드로 다루는 Base64
  3. SQL
코드

SQL에서 Base64 사용하기

주요 데이터베이스는 모두 Base64를 지원하지만, 함수 이름과 실패할 때의 동작이 저마다 다릅니다. 아래 결과는 MySQL 8.4, PostgreSQL 17, SQL Server 2022와 2025 기준입니다.

MySQL과 MariaDB: TO_BASE64와 FROM_BASE64

SELECT TO_BASE64('héllo wörld');
-- aMOpbGxvIHfDtnJsZA==   (connection charset utf8mb4)

SELECT CONVERT(FROM_BASE64('aMOpbGxvIHfDtnJsZA==') USING utf8mb4);
-- héllo wörld

TO_BASE64는 문자열의 바이트를 그 문자 집합 그대로 인코딩합니다. utf8mb4라면 UTF-8이 나오고, latin1 열이라면 Latin-1 바이트가 나옵니다(euckr 열이라면 EUC-KR 바이트). 그래서 TO_BASE64(CONVERT('héllo' USING latin1))은 aMOpbGxv가 아니라 aOlsbG8=를 반환합니다. FROM_BASE64는 바이너리 문자열을 반환하며, CONVERT(... USING utf8mb4)로 다시 텍스트로 바꿀 수 있습니다.

TO_BASE64는 MIME처럼 76자에서 줄을 바꿉니다.

SELECT LENGTH(TO_BASE64(REPEAT('x', 60)));            -- 81 (80 chars + 1 newline)
SELECT REPLACE(TO_BASE64(REPEAT('x', 60)), '\n', ''); -- single line, 80 chars

잘못된 입력은 오류를 일으키지 않습니다. FROM_BASE64는 NULL을 반환합니다.

입력결과
aGk=hi
aGkNULL (패딩 없음)
aGk=!!NULL
PDw_Pz8-Pg==NULL (URL-safe)
aNULL
aGl=hi (0이 아닌 패딩 비트 허용)
'aGVs\nbG8K', 'aGVs bG8K'hello\n (공백 무시)

문자열 함수로 URL-safe 변환하기:

SELECT TRIM(TRAILING '=' FROM REPLACE(REPLACE(TO_BASE64('<<???>>'), '+', '-'), '/', '_'));
-- PDw_Pz8-Pg

SELECT FROM_BASE64(CONCAT(
  REPLACE(REPLACE('PDw_Pz8-Pg', '-', '+'), '_', '/'),
  REPEAT('=', (4 - LENGTH('PDw_Pz8-Pg') % 4) % 4)));
-- <<???>>

값이 더 길다면 인코더도 REPLACE(..., '\n', '')로 감싸세요. 두 함수 모두 MySQL 5.6부터 있으며 MariaDB에도 있습니다.

PostgreSQL: encode와 decode

PostgreSQL은 bytea를 다룹니다. 텍스트는 convert_to로 바꾸고 convert_from으로 되돌리세요.

SELECT encode(convert_to('héllo wörld', 'UTF8'), 'base64');
-- aMOpbGxvIHfDtnJsZA==

SELECT convert_from(decode('aMOpbGxvIHfDtnJsZA==', 'base64'), 'UTF8');
-- héllo wörld

MySQL처럼 encode(..., 'base64')도 76자에서 줄을 바꾸며, psql은 줄 끝의 줄 바꿈을 +로 표시합니다. replace(encode(x, 'base64'), E'\n', '')로 제거하세요.

MySQL과 달리 잘못된 입력에는 오류가 납니다.

decode('aGk', 'base64')
ERROR:  invalid base64 end sequence
HINT:  Input data is missing padding, is truncated, or is otherwise corrupted.

decode('PDw_Pz8-Pg==', 'base64')
ERROR:  invalid symbol "_" found while decoding base64 sequence

aGk=!!는 invalid symbol "!"로, a는 invalid base64 end sequence로 실패합니다. 줄 바꿈과 공백을 포함한 공백 문자는 무시되며, aGl=는 허용됩니다.

PostgreSQL 17과 18에는 base64url 형식이 없으므로(unrecognized encoding: "base64url") translate로 변환하세요.

SELECT translate(rtrim(encode('<<???>>'::bytea, 'base64'), '='), '+/', '-_');
-- PDw_Pz8-Pg

SELECT convert_from(decode(
  rpad(translate('PDw_Pz8-Pg', '-_', '+/'), (length('PDw_Pz8-Pg') + 3) / 4 * 4, '='),
  'base64'), 'UTF8');
-- <<???>>

트랜잭션을 중단시키지 않고 검증하려면 NULL을 반환하는 EXCEPTION WHEN others 블록이 있는 PL/pgSQL 함수로 decode를 감싸세요.

SQL Server: XML base64Binary 기법

SQL Server 2025 이전에는 Base64 함수가 없습니다. XML 타입은 varbinary와 Base64인 xs:base64Binary 사이를 변환합니다.

-- encode
DECLARE @bin varbinary(max) = CAST('hi' AS varbinary(max));
SELECT CAST('' AS xml).value('xs:base64Binary(sql:variable("@bin"))', 'varchar(max)');
-- aGk=

-- decode
DECLARE @b64 varchar(max) = 'aGk=';
SELECT CAST('' AS xml).value('xs:base64Binary(sql:variable("@b64"))', 'varbinary(max)');
-- 0x6869

FOR XML ... BINARY BASE64와 FOR JSON도 varbinary 열을 Base64로 내보냅니다. SELECT CAST('hi' AS varbinary(max)) AS bin FOR JSON PATH는 [{"bin":"aGk="}]를 반환합니다. XML 변환은 줄을 바꾸지 않습니다. 60바이트가 80자짜리 문자열 하나로 나왔습니다.

XML 메서드에는 QUOTED_IDENTIFIER ON이 필요합니다. sqlcmd는 기본값이 off라서 Msg 1934: SELECT failed because the following SET options have incorrect settings: 'QUOTED_IDENTIFIER'가 나옵니다. -I를 넘기거나 SET QUOTED_IDENTIFIER ON을 실행하세요.

SQL Server의 텍스트 인코딩

nvarchar는 UTF-16LE이므로 CAST(N'héllo wörld' AS varbinary(max))는 aADpAGwAbABvACAAdwD2AHIAbABkAA==로 인코딩되며, 다른 시스템에서 디코딩하면 글자 사이에 빈칸이 생깁니다. UTF-8이 필요하면(SQL Server 2019 이상) 먼저 UTF-8 데이터 정렬을 거치세요.

DECLARE @bin varbinary(max) = CAST(CAST(N'héllo wörld'
    COLLATE Latin1_General_100_CI_AS_SC_UTF8 AS varchar(max)) AS varbinary(max));
-- encodes to aMOpbGxvIHfDtnJsZA==

UTF-8을 다시 디코딩하려면 UTF-8 대상이 필요합니다. 기본 SQL_Latin1_General_CP1_CI_AS 데이터 정렬을 쓰는 데이터베이스에서 그냥 CAST(@raw AS varchar(max))를 하면 héllo wörld처럼 깨져 보입니다. varchar(max) COLLATE Latin1_General_100_CI_AS_SC_UTF8로 선언한 열에 바이트를 넣으면 héllo wörld가 나옵니다. UTF-16 데이터라면 CAST(@raw AS nvarchar(max))로 충분합니다.

오류

문자열 리터럴이라면 잘못된 Base64는 컴파일 시점에 실패합니다. Msg 9319: XQuery [value()]: Static simple type validation: Invalid simple type value 'aGk'. 같은 입력을 sql:variable로 넘기면 대신 NULL이 반환됩니다. 패딩 누락, URL-safe 문자(PDw_Pz8-Pg==), 0이 아닌 패딩 비트(aGl=)는 모두 거부되었고, 문자열 안의 줄 바꿈은 허용되었습니다.

SQL Server 2025: BASE64_ENCODE와 BASE64_DECODE

SQL Server 2025(17.x)와 Azure SQL에는 URL-safe 플래그까지 갖춘 진짜 함수가 추가되었습니다.

SELECT BASE64_ENCODE(0x3C3C3F3F3F3E3E);      -- PDw/Pz8+Pg==
SELECT BASE64_ENCODE(0x3C3C3F3F3F3E3E, 1);   -- PDw_Pz8-Pg   (url_safe, no padding)
SELECT BASE64_DECODE('PDw_Pz8-Pg');          -- 0x3C3C3F3F3F3E3E

BASE64_ENCODE는 varbinary만 받습니다. varchar를 넘기면 Msg 8116: Argument data type varchar(max) is invalid for argument 1 of base64_encode function으로 실패합니다. BASE64_DECODE는 두 알파벳을 패딩 유무와 관계없이 받으며 aGl=도 받습니다. aGk=!!나 a 같은 잘못된 입력은 Msg 9803: Invalid data for type "Base64Decode"를 일으킵니다.

데이터베이스 공통 함정

  • 입력의 문자 집합. 같은 텍스트라도 latin1 열, utf8mb4 열, nvarchar 열에서 서로 다른 Base64가 나옵니다. UTF-8 바이트로 정하고 명시적으로 변환하세요.
  • 숨은 줄 바꿈. MySQL과 PostgreSQL은 76자에서 줄을 바꿉니다. JSON 소비자와 HTTP 헤더는 그 안에 든 \n 때문에 깨집니다.
  • 조용한 NULL. MySQL과 SQL Server XML 기법은 잘못된 입력에 NULL을 반환하며, JOIN이나 WHERE가 이를 조용히 걸러 버립니다.
  • 큰 값. 쿼리에서 BLOB을 인코딩하면 네트워크로 33% 더 많은 데이터가 오갑니다. 저장된 값을 직접 확인하려면 Base64로 조회한 뒤 Base64 파일 변환이나 Base64 hex 변환으로 여세요.

자주 묻는 질문

MySQL FROM_BASE64가 NULL을 반환하는 이유는 무엇인가요?

MySQL은 잘못된 입력에 오류 대신 NULL을 반환합니다. 패딩 누락, URL-safe 문자 -나 _, 쓰레기 문자가 원인입니다. Base64 검사기로 입력을 확인하고, URL-safe 문자열은 디코딩 전에 REPLACE로 고치세요.

MySQL TO_BASE64 출력에 줄 바꿈이 들어가는 이유는 무엇인가요?

TO_BASE64는 MIME 관례를 따라 76자마다 줄 바꿈을 넣습니다. 한 줄 출력이 필요하면 REPLACE(TO_BASE64(x), '\n', '')로 감싸세요.

SQL Server에 Base64 함수가 있나요?

SQL Server 2025와 Azure SQL에는 BASE64_ENCODE와 BASE64_DECODE가 있습니다. 이전 버전에는 함수가 없지만 XML xs:base64Binary 변환으로 같은 일을 할 수 있습니다.

파일을 Base64로 데이터베이스에 저장해야 하나요?

대개는 아닙니다. 바이너리 열(BLOB, bytea, varbinary)은 같은 데이터를 약 25% 작게 저장하고 변환도 필요 없습니다. 텍스트가 필요한 시스템으로 보낼 때만 인코딩하세요. Base64 크기 증가를 참고하세요.

계속 읽기