
本文详细介绍了如何使用php将扁平化的sql联接查询结果转换为具有层级结构的嵌套数组,例如将问卷及其包含的问题组织成一个主从式数据结构。通过一个高效的单次遍历循环,利用父级id作为数组键进行条件判断和数据聚合,避免了重复数据并确保了正确的嵌套格式,最终生成符合预期的json输出。
在Web开发中,我们经常需要从关系型数据库中检索数据并将其组织成更符合前端展示或API接口需求的层级结构。一个常见的场景是,当存在“一对多”关系(如一个问卷包含多个问题)时,通过SQL JOIN 操作获取的数据通常是扁平化的,即每个子记录都会重复父记录的信息。本文将指导您如何高效地将这种扁平数据转换为嵌套的PHP数组结构。
假设我们有两个表:questionnaires (问卷) 和 questions (问题),它们之间通过一个联接表 questionnaireshasquestions 建立多对多关系。我们希望得到的数据结构是一个包含问卷信息(ID、标题)及其所有相关问题(ID、文本)的嵌套数组,类似以下JSON格式:
[
{
"id": "x",
"title": "x",
"questions": [
{"id": "x", "text": "x"},
{"id": "x2", "text": "x2"}
]
}
]为了获取所有问卷及其对应的问题,我们通常会使用 INNER JOIN 查询:
SELECT
questionnaires.id AS QuestionnaireId,
questionnaires.title AS QuestionnaireTitle,
questions.id AS QuestionId,
questions.text AS Question
FROM
questionnaires
INNER JOIN
questionnaireshasquestions qa ON qa.idQuestionnaire = questionnaires.id
INNER JOIN
questions ON questions.id = qa.idQuestion;这条查询会返回一个扁平化的结果集,其中每个问卷-问题对都会作为一行数据。例如,如果问卷A有3个问题,那么问卷A的信息会在结果集中出现3次。
立即学习“PHP免费学习笔记(深入)”;
许多初学者在处理这种扁平数据时,可能会尝试在循环中直接构建数组。一个常见的错误尝试如下:
$data = [];
while ($row = $conn->fetch()) {
if (!isset($data['questionnaires'][$row['QuestionnaireId']])) {
$data['questionnaires'][] = [
'id' => $row['QuestionnaireId'],
'title' => $row['QuestionnaireTitle'],
'questions' => [
'id' => $row['QuestionId'],
'text' => $row['Question']
]
];
} else {
// 这里的逻辑可能导致问题,例如覆盖或不正确的追加
$data['questionnaires'][$row['QuestionnaireId']][] = [
'questions' => [
'id' => $row['QuestionId'],
'text' => $row['Question']
]
];
}
}这种方法通常会导致以下问题:
解决上述问题的关键在于,使用父级记录的唯一ID作为临时数组的键,这样可以确保每个父级记录只被初始化一次,并且其子级记录可以正确地被追加到对应的子数组中。
以下是优化的PHP代码实现:
<?php
// 假设 $conn 是您的数据库连接对象,并且 $conn->fetch() 方法可以逐行获取查询结果
// 示例数据模拟,实际应用中替换为您的数据库查询循环
$rows = [
['QuestionnaireId' => '1', 'QuestionnaireTitle' => 'Are you hungry?', 'QuestionId' => '1', 'Question' => 'How is your passion?'],
['QuestionnaireId' => '1', 'QuestionnaireTitle' => 'Are you hungry?', 'QuestionId' => '2', 'Question' => 'Do you drink?'],
['QuestionnaireId' => '2', 'QuestionnaireTitle' => 'How are you feeling?', 'QuestionId' => '1', 'Question' => 'How is your passion?'],
['QuestionnaireId' => '2', 'QuestionnaireTitle' => 'How are you feeling?', 'QuestionId' => '3', 'Question' => 'Do you like fish?'],
['QuestionnaireId' => '5', 'QuestionnaireTitle' => 'Is testing working?', 'QuestionId' => '4', 'Question' => 'How is the testing?']
];
$data = ['questionnaires' => []]; // 初始化一个用于存放最终数据的数组
foreach ($rows as $row) { // 实际应用中替换为 while ($row = $conn->fetch())
$questionnaireId = $row['QuestionnaireId'];
// 检查当前问卷ID是否已经存在于 $data['questionnaires'] 中
if (!isset($data['questionnaires'][$questionnaireId])) {
// 如果是第一次遇到这个问卷ID,则初始化问卷信息
// 并为其 'questions' 字段初始化一个空数组,用于后续添加问题
$data['questionnaires'][$questionnaireId] = [
'id' => $row['QuestionnaireId'],
'title' => $row['QuestionnaireTitle'],
'questions' => [], // 初始化一个空数组来收集问题
];
}
// 将当前行的问题信息添加到对应问卷的 'questions' 数组中
$data['questionnaires'][$questionnaireId]['questions'][] = [
'id' => $row['QuestionId'],
'text' => $row['Question']
];
}
// 由于我们使用了问卷ID作为键,最终的 $data['questionnaires'] 会是一个关联数组
// 如果需要一个索引数组(数字键),可以使用 array_values()
$finalQuestionnaires = array_values($data['questionnaires']);
// 打印最终的JSON格式数据
echo json_encode($finalQuestionnaires, JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE);
?>代码解析:
经过上述处理,json_encode($finalQuestionnaires) 将生成如下结构的数据:
[
{
"id": "1",
"title": "Are you hungry?",
"questions": [
{
"id": "1",
"text": "How is your passion?"
},
{
"id": "2",
"text": "Do you drink?"
}
]
},
{
"id": "2",
"title": "How are you feeling?",
"questions": [
{
"id": "1",
"text": "How is your passion?"
},
{
"id": "3",
"text": "Do you like fish?"
}
]
},
{
"id": "5",
"title": "Is testing working?",
"questions": [
{
"id": "4",
"text": "How is the testing?"
}
]
}
]这正是我们期望的、结构清晰的嵌套数组格式。
通过利用父级记录的唯一ID作为临时数组的键,并巧妙地在循环中进行条件判断,我们能够高效且准确地将扁平化的SQL联接结果转换为复杂的嵌套PHP数组。这种模式在处理一对多关系数据时非常实用,能够帮助开发者构建出结构清晰、易于消费的数据接口。
以上就是PHP从SQL联接结果构建嵌套数组的有效方法的详细内容,更多请关注php中文网其它相关文章!
PHP怎么学习?PHP怎么入门?PHP在哪学?PHP怎么学才快?不用担心,这里为大家提供了PHP速学教程(入门到精通),有需要的小伙伴保存下载就能学习啦!
Copyright 2014-2025 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号