Php MySQL-如何修改父/子选择查询以将更多子项添加到现有数组/JSON?

Php MySQL-如何修改父/子选择查询以将更多子项添加到现有数组/JSON?,php,mysql,sql,json,d3.js,Php,Mysql,Sql,Json,D3.js,我的以下查询工作正常: SELECT core_condition AS name, NULL AS parent FROM condition_theme_lookup UNION ALL SELECT theme_name AS name, condition_theme_lookup.core_condition AS parent FROM theme, condition_theme_lookup UNION ALL SELECT strand.strand_name AS name,

我的以下查询工作正常:

SELECT core_condition AS name, NULL AS parent
FROM condition_theme_lookup
UNION ALL
SELECT theme_name AS name, condition_theme_lookup.core_condition AS parent
FROM theme, condition_theme_lookup
UNION ALL
SELECT strand.strand_name AS name, theme.theme_name AS parent
FROM strand
JOIN theme ON theme.theme_pk = strand.theme_fk
结果数组使用一些PHP生成以下JSON,到目前为止还可以,显示“主题”父级的“串”子级:

{
    "name": "Condition",
    "children": [{
        "name": "Professional",
        "children": [{
            "name": "Professional Behavours"
        }, {
            "name": "Self-Care and Self-Awareness"
        }, {
            "name": "Medical Ethics and Law"
        }]
    }, {
        "name": "Leader",
        "children": [{
            "name": "Teamwork and Leadership"
        }, {
            "name": "Collaborative Practice"
        }, {
            "name": "Health Systems and Careers"
        }]
    }, {
        "name": "Advocate",
        "children": [{
            "name": "Health Advocacy"
        }, {
            "name": "Aboriginal Health"
        }, {
            "name": "Diversity and Inequality"
        }, {
            "name": "Health Promotion"
        }]
    }, {
        "name": "Clinician",
        "children": [{
            "name": "Scientific Knowledge"
        }, {
            "name": "Patient Assessment and Clinical Reasoning"
        }, {
            "name": "Patient Management"
        }, {
            "name": "Patient Perspective"
        }, {
            "name": "Clinical Communication"
        }, {
            "name": "Quality Care"
        }]
    }, {
        "name": "Educator",
        "children": [{
            "name": "Life-Long Learning"
        }, {
            "name": "Mentoring Relationships"
        }, {
            "name": "Patient Education"
        }, {
            "name": "Teaching and Learning"
        }, {
            "name": "Assessment and Evaluation"
        }]
    }, {
        "name": "Scholar",
        "children": [{
            "name": "Research and Biostatistics"
        }, {
            "name": "Evidence-Based Practice"
        }, {
            "name": "Information Literacy"
        }]
    }]
}
现在,我想将表strand.Year中的“1年级”、“2年级”、“3年级”和“4年级”添加到每个strand.strand_家长姓名中,例如职业行为、医疗道德和法律等

我尝试了以下修改的查询:

SELECT core_condition AS name, NULL AS parent
FROM condition_theme_lookup
UNION ALL
SELECT theme_name AS name, condition_theme_lookup.core_condition AS parent
FROM theme, condition_theme_lookup
UNION ALL
SELECT strand.strand_name AS name, theme.theme_name AS parent
FROM strand, theme
UNION ALL
SELECT strand.year AS name, strand.strand_name AS parent
FROM strand
JOIN theme ON theme.theme_pk = strand.theme_fk
但正如你在下面看到的,现在的关系是不完整的;前五个节点失去了他们的孩子,只有一个环节,信息素养,有一年的孩子

   {
    "name": null,
    "children": [{
        "name": "Professional"
    }, {
        "name": "Leader"
    }, {
        "name": "Advocate"
    }, {
        "name": "Clinician"
    }, {
        "name": "Educator"
    }, {
        "name": "Scholar",
        "children": [{
            "name": "Professional Behavours"
        }, {
            "name": "Self-Care and Self-Awareness"
        }, {
            "name": "Teamwork and Leadership"
        }, {
            "name": "Collaborative Practice"
        }, {
            "name": "Health Systems and Careers"
        }, {
            "name": "Health Advocacy"
        }, {
            "name": "Aboriginal Health"
        }, {
            "name": "Diversity and Inequality"
        }, {
            "name": "Health Promotion"
        }, {
            "name": "Scientific Knowledge"
        }, {
            "name": "Patient Assessment and Clinical Reasoning"
        }, {
            "name": "Patient Management"
        }, {
            "name": "Patient Perspective"
        }, {
            "name": "Clinical Communication"
        }, {
            "name": "Quality Care"
        }, {
            "name": "Life-Long Learning"
        }, {
            "name": "Mentoring Relationships"
        }, {
            "name": "Patient Education"
        }, {
            "name": "Teaching and Learning"
        }, {
            "name": "Assessment and Evaluation"
        }, {
            "name": "Research and Biostatistics"
        }, {
            "name": "Evidence-Based Practice"
        }, {
            "name": "Information Literacy",
            "children": [{
                "name": "Year 1"
            }, {
                "name": "Year 2"
            }, {
                "name": "Year 3"
            }, {
                "name": "Year 4"
            }]
        }, {
            "name": "Medical Ethics and Law"
        }]
    }]
}
如何更改查询以显示第一个JSON中的所有关系,并将四个“Year X”子项的集合添加到每个串中

SQL:

JSON原始版本的可用PHP/MySQL是:

$condition = $_POST['condition'];

$query = "SELECT core_condition AS name, NULL AS parent
FROM condition_theme_lookup
UNION ALL
SELECT theme_name AS name, condition_theme_lookup.core_condition AS parent
FROM theme, condition_theme_lookup
UNION ALL
SELECT strand.strand_name AS name, theme.theme_name AS parent
FROM strand
JOIN theme ON theme.theme_pk = strand.theme_fk";
$result = $connection->query($query);
$data = array();
while ($row = $result->fetch_object()) {
     $data[$row->name] = $row;
 }

foreach ($data as $row) {   
    if ($row->name == 'Condition') {
        $row->name = $condition;
    }
    if ($row->parent === null) {
        $roots[]= $row;
    } else {
        $data[$row->parent]->children[] = $row;
    }
    unset($row->parent);
}

$json = json_encode($roots);

如果您确切知道您将在几年内使用哪些值,您可以在查询中创建假值:

SELECT *, 'Year 1' as year1, 'Year 2' as year2 from strands... and so on
正如我在my中所写的:名称在所有表中都应该是唯一的。这是一个假设,是基于你公司的样本数据。但strand表并非如此。如果某个名称在SQL结果集中出现多次,则在此将覆盖以前具有相同名称的行:

$data[$row->name] = $row;
因为$row->name具有相同的值。因此,您需要一列作为唯一标识符,并使用该列作为$data数组的索引。您不能使用名称,因为它在strand表中不是唯一的。并且不能使用主键,因为它们在所有表中都不是唯一的。但您可以使用表名或唯一的表别名和主键的组合,如

CONCAT('condition:', condition_theme_lookup_pk) AS global_id
...
CONCAT('theme:', theme_pk) AS global_id
....
CONCAT('strand:', strand_pk) AS global_id
父列应具有相同的模式

CONCAT('theme:', theme_fk) AS parent_global_id
下一个问题是——如何按主题按年份对链进行分组?嵌套逻辑不遵循模式parentTable name=$condition; } 如果$row->parent\u global\u id==null{ $roots[]=$row; }否则{ $data[$row->parent\u global\u id]->children[]=$row; } 取消设置$row->父项\u全局\u id; 取消设置$row->全局\u id; } $json=json_编码$root; 注:

结果将与链接中的结果不同。但我不知道,如果数据中没有任何相关信息,像Professional Behavour这样的strand行如何成为其他strand行的父行。 我用一个显式的交叉连接替换了逗号连接,这使意图更加清晰。这里的假设是条件主题查找表中只有一行。否则,您将需要一个连接条件,这对于给定的模式是不可能的。
您在评论中写道:在最终的JSON中还会有几个子级别。所有级别都必须遵循相同的嵌套逻辑,或者至少可以像年份一样进行转换。如果您有更多惊喜,那么解决方案可能不合适。在某些时候,我会考虑每个级别执行一个查询,并从叶子到根构建自底向上的层次结构。 MySQL 8-CTE+JSON支持 使用JSON_对象函数、JSON_ArrayAg聚合函数和公共表表达式CTE的组合,我们现在可以通过单个查询获得具有多个嵌套级别的嵌套JSON结果:

年复一年 选择 主题(fk), 年 json_Arrayagjson_对象“名称”,子对象为strand_名称 从斯特兰德 按主题分组,年份 ,主题为 选择 t、 主题(pk), t、 主题名称作为名称, json_Arrayagjson_对象“名称”,年份,“儿童”,儿童为儿童 来自主题t 在y.theme\u fk=t.theme\u pk上左键连接y 按t.theme\U pk分组 选择json_对象 “名称”,c.core_条件, 'children',json_arrayagjson_object'name',t.name',children',t.children 作为json 从条件主题查找c 交叉连接主题 按c.condition\u theme\u lookup\u pk分组 每个嵌套级别都封装在自己的CTE中,这提高了可读性。每个级别都可以有自己的嵌套逻辑。由于结果是一步一步地构建,所以添加更多级别应该不是什么大问题

使现代化 要在联合查询中交换股和年的级别,只需在最后两个子查询中进行少量更改:

... 选择不同的 CONCAT'theme:',theme_fk',strand:',strand_名称作为全局id, 以您的姓名作为姓名, CONCAT'theme:',主题作为父项\u全局\u id 从斯特兰德 联合所有 选择CONCAT'strand\u year:',strand\u pk作为全局\u id, 以年份作为名称, CONCAT'theme:',theme_fk',strand:',strand_名称作为父项\u全局\u id 从斯特兰德 如果需要以特定的方式对节点的子节点进行排序,但级别不同,我建议在每个子查询中添加两列num_sort和str_sort。例如,如果您希望主题按主键排序-添加

theme_pk as num_sort, '' as str_sort
如果钢绞线应按名称排序-添加

0 as num_sort, strand_name as str_sort
如果年份应按值排序,但以自然方式排序,则第10年>第2年

cast(replace(year, 'Year ', '') as signed) as num_sort, '' as str_sort
然后按num\u排序追加顺序 ,str_排序到查询

然后需要从PHP对象中删除这些列属性

取消设置$row->父项\u全局\u id; 取消设置$row->全局\u id; 取消设置$row->num\U排序; 取消设置$row->STRU排序;
当您试图向原始查询添加额外的部分时,应该在连接部分之后而不是之前完成。联接属于上一个查询。此版本应适用于:

SELECT core_condition AS name, NULL AS parent
FROM condition_theme_lookup
UNION ALL
SELECT theme_name AS name, condition_theme_lookup.core_condition AS parent
FROM theme, condition_theme_lookup
UNION ALL
SELECT strand.strand_name AS name, theme.theme_name AS parent
FROM strand
JOIN theme ON theme.theme_pk = strand.theme_fk
-- beginning of added query --
UNION ALL
SELECT strand.year AS name, strand.strand_name AS parent
FROM strand WHERE strand.year is not NULL;

我还添加了strand.year不为NULL的条件-如果您确定所有记录都设置了年份,请跳过这一部分。

您不应该在年份表和其他记录之间建立关系吗。这里没有外键,您打算如何为每个链项目获取正确的年份信息?请检查下面的答案。如果你需要一段关系,那么就去建立它。如果没有,那么就使用下面的解决方案。我意识到年份信息只在strand表下面。如果要进行联合,则需要相同数量的列,因此每个表都会有年份字段,而这不是您想要的。如果您知道它不会改变,为什么不以编程方式处理它,而不是在查询中处理它?最终的JSON中会有多个子级别,因此,我更希望所有内容都来自DB查询。我已经修改了OP,以反映strand表的年份。再次感谢Paul!这些看起来像是可行的解决方案,特别是MySQL 8,我在UWA的服务器上还没有。考虑到其他需要添加的级别的长期解决方案,那么MySQL 8看起来是一个不错的选择。不过,在星期三AWST我回到办公室之前,我无法测试你的第一个解决方案。但两者看起来都是交易。谢谢,PeterOh,MySQL 8解决方案的顺序或关系不正确。它应该是Condition为top,然后是theme->strand->year,而不是theme->year-strand…在这个D3.js示例中,我手动构建了JSON,不幸的是,JSON_ARRAYAGG不支持ORDER BY子句。解决方法是使用组_CONCAT和一些铸造:-我没有添加这个答案,因为它已经太长了。看起来不正确。下一个级别的父级\u全局\u id应与最后一个级别的全局\u id匹配,即CONCAT'strand\u year:',strand\u pk。从单位来看,股线是交叉连接。我怀疑你是否想要那样。