如何将 oci_fetch_assoc 数据转换为 DataTable JSON
数据小许
结论
问题不在 oci_fetch_assoc(),而是 json_encode() 写在了取数循环里。程序每获取一行就输出一次 JSON,最终响应会变成多个 JSON object 的直接拼接,这不是有效的 JSON 文档。
处理方式如下:
- 在循环中收集数据;
- 根据 DataTables 的列配置生成数组行或对象行;
- 循环结束后,只调用一次
json_encode()和echo。
生成二维数组格式
如果 DataTables 使用默认的数组行格式,建议明确指定每一列,以免字段顺序发生变化:
<?php
header('Content-Type: application/json; charset=utf-8');
$data = [];
while (($row = oci_fetch_assoc($stid)) !== false) {
$data[] = [
$row['SCHEMA'],
$row['TABLE_NAME'],
$row['CUSTOMFIELD10'],
$row['CUSTOMFIELD5'],
$row['CUSTOMFIELD9'],
$row['LAST_UPD_TIME']
];
}
$response = [
'data' => $data
];
echo json_encode(
$response,
JSON_UNESCAPED_UNICODE | JSON_INVALID_UTF8_SUBSTITUTE
);
exit;
输出结果类似:
{
"data": [
[
"TEST",
"TEST_T",
"CREATING",
"NIK",
"NIK",
"27-JUN-18"
],
[
"TEST",
"ART_CM3_T",
"Average DWP",
null,
"BILLING",
"05-FEB-19"
]
]
}
前端列的排列顺序必须与 PHP 数组中元素的排列顺序一致:
$('#example').DataTable({
ajax: 'data.php',
columns: [
{ title: 'Schema' },
{ title: 'Table Name' },
{ title: 'Custom Field 10' },
{ title: 'Custom Field 5' },
{ title: 'Custom Field 9' },
{ title: 'Last Update Time' }
]
});
也可以通过 array_values($row) 转换:
$data[] = array_values($row);
不过,不建议依赖它来确定列顺序。只要 SQL 查询字段的顺序发生变化,DataTables 中的数据就可能出现在错误的列里。明确列出字段会更稳妥。
也可以直接使用对象格式
DataTables 不要求每一行都必须是数组。oci_fetch_assoc() 返回的关联数组也可以直接使用,只需在前端通过 columns.data 指定字段名。
PHP:
<?php
header('Content-Type: application/json; charset=utf-8');
$data = [];
while (($row = oci_fetch_assoc($stid)) !== false) {
$data[] = $row;
}
echo json_encode(
['data' => $data],
JSON_UNESCAPED_UNICODE | JSON_INVALID_UTF8_SUBSTITUTE
);
exit;
对应的 JSON:
{
"data": [
{
"SCHEMA": "TEST",
"TABLE_NAME": "TEST_T",
"CUSTOMFIELD10": "CREATING",
"CUSTOMFIELD5": "NIK",
"CUSTOMFIELD9": "NIK",
"LAST_UPD_TIME": "27-JUN-18"
}
]
}
DataTables 配置:
$('#example').DataTable({
ajax: 'data.php',
columns: [
{ data: 'SCHEMA', title: 'Schema' },
{ data: 'TABLE_NAME', title: 'Table Name' },
{ data: 'CUSTOMFIELD10', title: 'Custom Field 10' },
{ data: 'CUSTOMFIELD5', title: 'Custom Field 5' },
{ data: 'CUSTOMFIELD9', title: 'Custom Field 9' },
{ data: 'LAST_UPD_TIME', title: 'Last Update Time' }
]
});
这种格式通常更容易维护,因为前端按字段名匹配列,不依赖数组中的位置。
当前响应为什么无效
当前响应实际是这样的:
{"data":[...]}{"data":[...]}{"data":[...]}
每一段单独看都是 JSON object,但将多个 JSON object 直接拼在一起后,结果就不再是有效的 JSON 文档。DataTables 发起 Ajax 请求时,需要解析一个完整的顶层 JSON 值。
出现这种结果,通常是因为代码写成了下面这样:
while (($row = oci_fetch_assoc($stid)) !== false) {
$data[] = $row;
echo json_encode(['data' => $data]);
}
应当把 echo 移到循环外:
while (($row = oci_fetch_assoc($stid)) !== false) {
$data[] = $row;
}
echo json_encode(['data' => $data]);
完整的错误处理示例
为了避免数据库错误或编码问题导致响应无法解析,可以统一返回 JSON:
<?php
header('Content-Type: application/json; charset=utf-8');
$data = [];
while (($row = oci_fetch_assoc($stid)) !== false) {
$data[] = [
$row['SCHEMA'],
$row['TABLE_NAME'],
$row['CUSTOMFIELD10'],
$row['CUSTOMFIELD5'],
$row['CUSTOMFIELD9'],
$row['LAST_UPD_TIME']
];
}
try {
echo json_encode(
['data' => $data],
JSON_UNESCAPED_UNICODE
| JSON_INVALID_UTF8_SUBSTITUTE
| JSON_THROW_ON_ERROR
);
} catch (JsonException $e) {
http_response_code(500);
echo json_encode([
'data' => [],
'error' => 'JSON encoding failed'
]);
}
exit;
JSON_THROW_ON_ERROR 需要 PHP 版本支持。如果运行环境较旧,可以使用 json_last_error() 和 json_last_error_msg() 检查编码错误。
注意事项
- JSON 接口中不能混入调试信息、HTML、PHP warning、BOM 或多余的
echo,否则 DataTables 可能提示Invalid JSON response。 null是合法的 JSON 值。Oracle 字段为空时,通常无须额外转换。- 如果部分空字段没有出现在结果中,可根据实际使用的 OCI8 调用方式,检查是否需要启用
OCI_RETURN_NULLS。 - Oracle
DATE字段的显示格式可能受当前会话的NLS_DATE_FORMAT影响。如果需要固定格式,建议在 SQL 中明确使用TO_CHAR()。 - 使用二维数组时,前后端必须严格保持列顺序一致。使用对象行时,则要正确配置
columns.data。 - 无论选择哪种格式,整个 PHP 请求最终只能输出一个完整的 JSON object。
备注:内容仅供参考。
