我的以下查询正常运行:
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,到目前为止,此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
中的'Year 1','Year 2','Year 3'和'Year 4'添加到每个strand.strand_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, theme
UNION ALL
SELECT strand.year AS name, strand.strand_name AS parent
FROM strand
JOIN theme ON theme.theme_pk = strand.theme_fk
但是,正如您在下面看到的那样,关系现在不完整;前五个节点失去了孩子,只有一串信息素养拥有Year儿童。
{
"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”子级的集合?
Required JSON result up to Year children (ignore children of 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);
答案 0 :(得分:1)
正如我在other answer中写道:“名称在所有表中都应该是唯一的”。这是根据您的previous question中的示例数据得出的假设。但是strand
表不是这种情况。如果一个名称在SQL结果集中出现多次,则以前具有相同名称的行将在此处被覆盖:
$data[$row->name] = $row;
因为$row->name
具有相同的值。因此,您需要一列作为唯一标识符,并将该列用作$data
数组的索引。您不能使用name
,因为它在strand
表中不是唯一的。而且您不能使用主键,因为它们在所有表中都不唯一。但是您可以结合使用表名(或唯一的表别名)和主键,如
CONCAT('condition:', condition_theme_lookup_pk) AS global_id
...
CONCAT('theme:', theme_pk) AS global_id
....
CONCAT('strand:', strand_pk) AS global_id
parent
列应具有相同的模式
CONCAT('theme:', theme_fk) AS parent_global_id
下一个问题是-如何按主题每年对绞线进行分组?嵌套逻辑不遵循模式parentTable <- childTable <- grandChildTable
。那将是condition <- theme <- year <- strand
。而是在一个表中有两个级别(年份和链名称)。您需要使用DISTINCT查询从strand
表中“提取”年份,就像它们存储在单独的表中一样。唯一标识符应该是主题PK和年份的组合。各个链应该在父列中引用这些标识符。最终查询将是
SELECT CONCAT('condition:', condition_theme_lookup_pk) AS global_id,
core_condition AS name,
NULL AS parent_global_id
FROM condition_theme_lookup
UNION ALL
SELECT CONCAT('theme:', theme_pk) AS global_id,
theme_name AS name,
CONCAT('condition:', condition_theme_lookup_pk) AS parent_global_id
FROM theme CROSS JOIN condition_theme_lookup
UNION ALL
SELECT DISTINCT
CONCAT('theme:', theme_fk, ',year:', strand.year) AS global_id,
strand.year AS name,
CONCAT('theme:', theme_fk) AS parent_global_id
FROM strand
UNION ALL
SELECT CONCAT('strand:', strand_pk) AS global_id,
strand.strand_name AS name,
CONCAT('theme:', theme_fk, ',year:', strand.year) AS parent_global_id
FROM strand
结果看起来像
global_id | name | parent_global_id
--------------------|------------------------------|---------------------
condition:1 | Condition | null
theme:1 | Professional | condition:1
theme:2 | Leader | condition:1
...
theme:1,year:Year 1 | Year 1 | theme:1
theme:2,year:Year 1 | Year 1 | theme:2
...
theme:1,year:Year 2 | Year 2 | theme:1
theme:2,year:Year 2 | Year 2 | theme:2
...
strand:1 | Professional Behavours | theme:1,year:Year 1
strand:2 | Self-Care and Self-Awareness | theme:1,year:Year 1
strand:3 | Teamwork and Leadership | theme:2,year:Year 1
strand:4 | Collaborative Practice | theme:2,year:Year 1
...
strand:27 | Teamwork and Leadership | theme:2,year:Year 2
您看到-“团队合作和领导力”出现两次。但是这两行具有不同的global_id
和不同的parent_global_id
。您还可以看到parent_global_id
如何明确引用父行的global_id
。
结果基本上是一个由不同表中的数据组成的邻接表。这些模式很容易转换成PHP中的嵌套结构。 PHP代码几乎不需要更改即可调整为新列:
$result = $connection->query($query);
$data = array();
while ($row = $result->fetch_object()) {
$data[$row->global_id] = $row;
}
$roots = [];
foreach ($data as $row) {
if ($row->name == 'Condition') {
$row->name = $condition;
}
if ($row->parent_global_id === null) {
$roots[]= $row;
} else {
$data[$row->parent_global_id]->children[] = $row;
}
unset($row->parent_global_id);
unset($row->global_id);
}
$json = json_encode($roots);
注意:
CROSS JOIN
替换了您的逗号联接,这使意图更加清晰。这里的假设是condition_theme_lookup
表中只有一行。否则,您将需要一个JOIN条件,这对于给定的架构是不可能的。使用JSON_OBJECT()
函数,JSON_ARRAYAGG()
聚合函数和公用表表达式(CTE)的组合,我们现在可以通过单个查询获得具有多个嵌套级别的嵌套JSON结果:>
with years as (
select
theme_fk,
year,
json_arrayagg(json_object('name', strand_name)) as children
from strand
group by theme_fk, year
), themes as (
select
t.theme_pk,
t.theme_name as name,
json_arrayagg(json_object('name', year, 'children', children)) as children
from theme t
left join years y on y.theme_fk = t.theme_pk
group by t.theme_pk
)
select json_object(
'name', c.core_condition,
'children', json_arrayagg(json_object('name', t.name, 'children', t.children))
) as json
from condition_theme_lookup c
cross join themes t
group by c.condition_theme_lookup_pk
每个嵌套级别都包装在其自己的CTE中,从而提高了可读性。每个级别都可以有自己的嵌套逻辑。由于结果是逐步构建的,因此添加更多级别并不重要。
要交换UNION查询中的股数和年份,在最后两个子查询中只需要很少的更改:
...
SELECT DISTINCT
CONCAT('theme:', theme_fk, ',strand:', strand_name) AS global_id,
strand_name AS name,
CONCAT('theme:', theme_fk) AS parent_global_id
FROM strand
UNION ALL
SELECT CONCAT('strand_year:', strand_pk) AS global_id,
strand.year AS name,
CONCAT('theme:', theme_fk, ',strand:', strand_name) AS parent_global_id
FROM strand
如果您需要以特定方式对节点的子级进行排序,但是对于级别进行不同的排序,则建议为每个子查询添加两列(num_sort
和str_sort
)。例如,如果您希望主题按其PK排序-添加
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
然后将ORDER BY num_sort, str_sort
附加到查询中。
然后,您需要从PHP对象中删除这些列(属性)
unset($row->parent_global_id);
unset($row->global_id);
unset($row->num_sort);
unset($row->str_sort);
答案 1 :(得分:0)
如果您确切知道要使用的值(年),则可以在查询中创建(伪造)它们:
x
答案 2 :(得分:0)
当您尝试向原始查询中添加额外的部分时-应该在“ JOIN”部分之后而不是之前进行。 “ JOIN”属于先前的查询。此版本应该可以工作:
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;
我还添加了条件“ WHEREstrand.year不为NULL”-如果您确定所有记录都设置了年份,请跳过此部分。