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, поэтому TO_BASE64(CONVERT('héllo' USING latin1)) возвращает aOlsbG8= вместо aMOpbGxv. FROM_BASE64 возвращает двоичную строку; обратно в текст её превращает CONVERT(... USING utf8mb4).
TO_BASE64 переносит строки через 76 символов, как MIME:
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 |
aGk | NULL (нет дополнения) |
aGk=!! | NULL |
PDw_Pz8-Pg== | NULL (URL-safe) |
a | NULL |
aGl= | hi (ненулевые биты дополнения допускаются) |
'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');
-- <<???>>
Чтобы проверять строки, не прерывая транзакцию, оберните decode в функцию на PL/pgSQL с блоком EXCEPTION WHEN others, который возвращает NULL.
SQL Server: трюк с XML base64Binary
До SQL Server 2025 функции для Base64 нет. Тип XML умеет преобразовывать между varbinary и xs:base64Binary, а это и есть Base64:
-- 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 он по умолчанию выключен, и вы получите 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 collation:
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. Обычный CAST(@raw AS varchar(max)) в базе с collation по умолчанию SQL_Latin1_General_CP1_CI_AS показывает 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==) и ненулевые биты дополнения (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".
Подводные камни во всех СУБД
- Кодировка входных данных. Один и тот же текст даёт разный Base64 в столбце
latin1, столбцеutf8mb4и столбцеnvarchar. Договоритесь о байтах UTF-8 и преобразуйте явно. - Скрытые переводы строк. MySQL и PostgreSQL переносят строки через 76 символов. Потребители JSON и HTTP-заголовки ломаются на встроенном
\n. - Молчаливые
NULL. MySQL и трюк с XML в SQL Server возвращаютNULLна плохих данных, аJOINилиWHEREтакие строки тихо отбрасывают. - Большие значения. Кодирование BLOB в запросе гонит по сети на 33% больше данных. Чтобы вручную проверить сохранённое значение, выберите его в Base64 и откройте инструментом Base64 в файл или Base64 в hex.
Вопросы и ответы
Почему FROM_BASE64 в MySQL возвращает NULL?
На некорректных данных MySQL возвращает NULL вместо ошибки: при отсутствии дополнения, URL-safe символах - или _ и мусорных символах. Проверьте строку валидатором Base64, а URL-safe строки перед декодированием исправьте через REPLACE.
Почему в выводе TO_BASE64 в MySQL есть переносы строк?
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.