上传文件
  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 字节,所以 TO_BASE64(CONVERT('héllo' USING latin1)) 返回 aOlsbG8=,而不是 aMOpbGxv。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 安全)
aNULL
aGl=hi(接受不为零的填充位)
'aGVs\nbG8K'、'aGVs bG8K'hello\n(忽略空白)

用字符串函数进行 URL 安全转换:

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 排序规则:

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 安全字符(PDw_Pz8-Pg==)和不为零的填充位(aGl=)都会被拒绝;字符串中的换行符则会被接受。

SQL Server 2025:BASE64_ENCODE 与 BASE64_DECODE

SQL Server 2025(17.x)和 Azure SQL 加入了真正的函数,还带有 URL 安全标志:

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 安全的 - 或 _,或者有垃圾字符。请用 Base64 校验工具 检查输入,并在解码前用 REPLACE 修正 URL 安全的字符串。

为什么 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 体积开销。

继续阅读