PAYATHON 2026

如何将 oci_fetch_assoc 数据转换为 DataTable JSON

数据小许

结论

问题不在 oci_fetch_assoc(),而是 json_encode() 写在了取数循环里。程序每获取一行就输出一次 JSON,最终响应会变成多个 JSON object 的直接拼接,这不是有效的 JSON 文档。

处理方式如下:

  1. 在循环中收集数据;
  2. 根据 DataTables 的列配置生成数组行或对象行;
  3. 循环结束后,只调用一次 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。

备注:内容仅供参考。