MYSQL复杂联盟

时间:2019-06-05 04:35:02

标签: php mysql sql

到目前为止,我可以使用以下MySQL查询:

SELECT CONCAT('program:', program_pk) AS global_id,
       program_name AS name,
       NULL AS parent_global_id
FROM program
UNION ALL
SELECT CONCAT('theme:', theme_pk) AS global_id,
       theme_name AS name,
       CONCAT('program:', program_pk) AS parent_global_id
FROM theme CROSS JOIN program
UNION ALL
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
UNION ALL
SELECT CONCAT('strand_year:', strand_pk, ',unit:', unit_pk) AS global_id,
       CONCAT(unit.unit_code, ' ', unit.unit_name) AS name,
       CONCAT('strand_year:', strand_pk) AS parent_global_id
FROM strand LEFT JOIN unit ON strand.year = unit.year

db-fiddle

表格程序

+------------+--------------+
| program_pk | program_name |
+------------+--------------+

表格主题

+----------+------------+
| theme_pk | theme_name |
+----------+------------+

表链

+-----------+-------------+----------+------+
| strand_pk | strand_name | theme_fk | year |
+-----------+-------------+----------+------+

表格单位

+---------+-----------+-----------+--------+------+----------+
| unit_pk | unit_code | unit_name | points | year | theme_fk |
+---------+-----------+-----------+--------+------+----------+

关系是:

程序->主题->链->年->单位

我现在需要向表中添加表learning_event

表learning_event

+-------------------+---------------------+---------+-----------+----------------+
    | learning_event_pk | learning_event_name | unit_fk | strand_fk | core_condition |
    +-------------------+---------------------+---------+-----------+----------------+

将来自父unit的学习事件分支给:

程序->主题->链->年->单位->学习活动

请注意,对于给定的链和单位,仅应显示与链相关的学习事件。

我已经玩过这个游戏了,但是真的不确定如何将它与学习活动与单元和链相关联。

更新

在JSON格式下,现有查询的内容如下:

{
    "name": "MD",
    "children": [{
        "name": "Professional",
        "children": [{
            "name": "Professional Behavours",
            "children": [{
                "name": "Year 1",
                "children": [{
                    "name": "IMED4443 Integrated Medical Sciences 1"
                }, {
                    "name": "IMED4444 Integrated Medical Sciences 2"
                }]
            }

我正在寻找的新输出如下:

"name": "MD",
"children": [{
        "name": "Professional",
        "children": [{
                "name": "Professional Behavours",
                "children": [{
                        "name": "Year 1",
                        "children": [{
                                "name": "IMED4443 Integrated Medical Sciences 1"
                            }, {
                                "name": "IMED4444 Integrated Medical Sciences 2",
                                "children": [{
                                    "name": "Lecture - CVS"
                                }, {
                                    "name": "Lecture - Type 1 Diabetes"
                                }...

并且学习事件仅应显示与单位和链的关系。

仅供参考,使用以下方式处理关系:

$result = $connection->query($query);
$data = array();
while ($row = $result->fetch_object()) {
    $data[$row->global_id] = $row;
}

$roots = array();
foreach ($data as $row) {   
    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);

新更新

该查询由Jonathan Willcock提供并由我修改,它很接近,它显示了所有主题和子线的年,以及第一个主题“ Professional”的单元和学习事件,但未显示单位其他主题。

SELECT CONCAT('program:', program_pk) AS global_id,
       program_name AS name,
       NULL AS parent_global_id
FROM program
UNION ALL
SELECT CONCAT('theme:', theme_pk) AS global_id,
       theme_name AS name,
       CONCAT('program:', program_fk) AS parent_global_id
FROM theme 
UNION ALL
SELECT 
       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('theme:', theme_fk, ',strand:', strand_name, ',strandyear:', strandyear_name) AS global_id,
       strandyear_name AS name,
       CONCAT('theme:', theme_fk, ',strand:', strand_name) AS parent_global_id
FROM strandyear sy 
INNER JOIN strand s ON s.strand_pk = sy.strand_fk

UNION ALL
SELECT 
       CONCAT('theme:', theme_fk, ',strand:', strand_name, ',strandyear:', strandyear_name, ',unit:', unit_name) AS global_id,
       unit_name AS name,
       CONCAT('theme:', theme_fk, ',strand:', strand_name, ',strandyear:', strandyear_name) AS parent_global_id
FROM unit u 
INNER JOIN strandyear sy ON u.strandyear_fk = sy.strandyear_pk
INNER JOIN strand s ON s.strand_pk = sy.strand_fk

UNION ALL
SELECT 
       CONCAT('theme:', theme_fk, ',strand:', strand_name, ',strandyear:', strandyear_name, ',unit:', unit_name, ',learning_event:', learning_event_name) AS global_id,
       learning_event_name AS name,
       CONCAT('theme:', theme_fk, ',strand:', strand_name, ',strandyear:', strandyear_name, ',unit:', unit_name) AS parent_global_id
FROM learning_event le
INNER JOIN unit u ON u.unit_pk = le.unit_fk
INNER JOIN strandyear sy ON u.strandyear_fk = sy.strandyear_pk
INNER JOIN strand s ON s.strand_pk = sy.strand_fk

db-fiddle

请注意,parent_global_id必须与前面的global_id相同。

最后更新

上面的查询工作正常!问题是单位表。更新db-fiddle

2 个答案:

答案 0 :(得分:1)

如果所需的层次结构是程序->主题->链->年->单位-> learning_event,则应调整表结构以反映此情况。特别是主题应该在主题和程序之间具有外键关系,并且您需要一年的额外级别。在主题和程序之间使用外键避免了交叉连接的需要。交叉连接有一种咬你的习惯,通常应避免。

如果您查看此db fiddle,将会发现我已经进行了这些更改。我曾称年级为stryearyear以避免使用保留字,但其意图应明确。现在,联接变为内部联接(而不是左联接),以从树中的更高级别中获取描述值,并且最低级别(learning_events)自动仅包含与strand,year和unit匹配的值,除了其他原因外通过简单的权宜之计,即每个级别在上一层都有一个外键,结构本身就可以保证它。

请注意,外键有效地链接了链接。例如,您不需要在learning_event和strand之间使用特定的外键,因为链中的中间键可以保证这种关系。

答案 1 :(得分:0)

假设program -> theme -> strand -> year -> unit -> learning event表示

  • 一个program具有1个或多个themes
  • 一个theme有1个或更多strands 等等

那么你需要

CREATE TABLE program (program_id ...)
CREATE TABLE theme   (theme_id ...,  program_id, ...)
CREATE TABLE strand  (strand_id ..., theme_id, ...)
etc

这在每对连续的一对表之间实现了1:1:1的关系。

一个典型的例子会更详细:

CREATE TABLE theme (
    theme_id INT UNSIGNED AUTO_INCREMENT NOT NULL,
    theme_name VARCHAR(99) NOT NULL,
    program_id INT UNSIGNED NOT NULL,   -- link to the program this theme is in
    PRIMARY KEY(theme_id)
) ENGINE=InnoDB

((您可以选择添加FOREIGN KEY约束,以进一步强调我包含的评论。)