【问题标题】:MYSQL complex UnionMYSQL复杂联盟
【发布时间】:2019-06-05 04:35:02
【问题描述】:

到目前为止,我有以下 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_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 提供并由我修改,很接近,它显示了所有主题和链的年份,以及第一个主题“专业”的单元和学习事件,但单元没有显示对于任何其他主题。

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

【问题讨论】:

  • 您确定 UNION ALL 是建立您所描述的关系的正确方法吗?很难说出你想要做什么,因为没有关于你想要的结果的信息。在您的情况下,似乎加入会更合适。如果您可以共享预期最终输出的样本,那么提供一些帮助会更容易,因为 UNION 将您的所有层次结构都放在同一级别,如果不应用一些,您将无法确定之后是什么围绕您的全局父 ID 的某种逻辑。
  • 查看更新的 OP...
  • 为什么单元有一个theme_fk?
  • 很高兴你捡到它...它是作为测试放入的,它没有被使用。
  • 嗯?没有名为children 的列。向我们展示SELECT 的输出。

标签: php mysql sql


【解决方案1】:

如果您想要的层次结构是程序 -> 主题 -> 链 -> 年份 -> 单元 -> 学习事件,那么您应该调整表结构以反映这一点。特别是主题,主题和节目之间应该有外键关系,并且需要额外的一年级。在主题和程序之间有一个外键可以避免交叉连接的需要。交叉连接有咬你的习惯,一般要避免。

如果您查看此db fiddle,您会发现我进行了这些更改。我已将年份级别称为 strandyear 以避免使用保留字,但意图应该是明确的。现在连接变为内连接(而不是左连接)以从树中的更高级别获取描述值,而底层(learning_events)自动只包含匹配链、年和单位的值,没有其他原因结构本身通过简单的权宜之计来保证它,每个级别都有一个外键到上一个级别。

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

【讨论】:

  • 我可以看到这个逻辑,并且你的小提琴中的结果看起来不错,但是我的 JSON 现在没有返回任何内容。这可能与 PHP 处理查询结果的逻辑有关...
  • 我确实删除了相关表,并使用您的 SQL 小提琴查询插入了重新创建...并使用了您的查询逐字逐句
  • 这是我现在从更改后的表和您的新查询中得到的 JSON:130.95.21.120/md/json/data_test.json 在股线之后什么都没有注意到...
  • 我认为您需要做的是将 strandyear 表中的列名从 year_name 更改为 strandyear_name 。我已经更新了小提琴。
  • 好的,数组 $data 显示链后的年份等 healthed.hms.uwa.edu.au/md/json/generate_array_test.php 但是,将该数组转换为子父层次结构的 PHP 在链后没有显示任何内容,请参阅 healthed.hms.uwa.edu.au/md/json/data_test.json
【解决方案2】:

假设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:many 关系。

一个典型的,更详细地说:

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 约束以进一步强调我包含的评论。)

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2017-03-11
    • 2013-08-24
    • 2013-03-01
    • 2021-12-28
    • 2011-03-19
    • 1970-01-01
    • 2011-11-19
    相关资源
    最近更新 更多