我有一个查询,它从如下表中生成分层结果:
- 程序
- 年
- 单位
- rotation_discipline_block
- 周
- 学习事件
- 周
- rotation_discipline_block
- 单位
- 年
但是,并非表 learning_event
中列 learning_event.week_fk
的所有记录都与表 week
中的记录有关系。例如 week_fk
可能为空或 0
在这种情况下,我想使用 learning_event.rotation_discipline_block_fk
中的值将表 learning_event
中的记录与表 rotation_discipline_block
中的记录相匹配为这些记录生成修改后的层次结构:
- 程序
- 年
- 单位
- rotation_discipline_block
- 学习事件
- rotation_discipline_block
- 单位
- 年
表learning_event
:
+-------------------+-----------------------+------------------------+----------+------------------------------+
| learning_event_pk | learning_event_name | learning_event_outcome | week_fk | rotation_discipline_block_fk |
+-------------------+-----------------------+------------------------+----------+------------------------------+
表周
:
+---------+-----------+------------------------------+
| week_pk | week_name | rotation_dicsipline_block_fk |
+---------+-----------+------------------------------+
表rotation_discipline_block
:
+------------------------------+--------------------------------+---------+
| rotation_discipline_block_pk | rotation_discipline_block_name | unit_fk |
+------------------------------+--------------------------------+---------+
表格单位
:
+---------+-----------+---------+
| unit_pk | unit_name | year_fk |
+---------+-----------+---------+
表年份
:
+---------+-----------+------------+
| year_pk | year_name | program_fk |
+---------+-----------+------------+
表程序
:
+------------+--------------+
| program_pk | program_name |
+------------+--------------+
我需要如何更改下面的查询才能执行此操作?
SELECT CONCAT('program:', program_pk) AS global_id,
program_name AS name,
NULL AS parent_global_id,
1 AS seq
FROM program
UNION ALL
SELECT CONCAT('year:', year_pk) AS global_id,
year_name AS name,
CONCAT('program:', program_fk) AS parent_global_id,
2 AS seq
FROM year
UNION ALL
SELECT
CONCAT('year:', year_fk, ',unit:', unit_name) AS global_id,
unit_name AS name,
CONCAT('year:', year_fk) AS parent_global_id,
3 AS seq
FROM unit
UNION ALL
SELECT
CONCAT('year:', year_fk, ',unit:', unit_name, ',rotation_discipline_block:', rotation_discipline_block_name) AS global_id,
rotation_discipline_block_name AS name,
CONCAT('year:', year_fk, ',unit:', unit_name) AS parent_global_id,
4 AS seq
FROM rotation_discipline_block rdb
INNER JOIN unit u ON u.unit_pk = rdb.unit_fk
UNION ALL
SELECT
CONCAT('year:', year_fk, ',unit:', unit_name, ',rotation_discipline_block:', rotation_discipline_block_name, ',week:', week_name) AS global_id,
week_name AS name,
CONCAT('year:', year_fk, ',unit:', unit_name, ',rotation_discipline_block:', rotation_discipline_block_name) AS parent_global_id,
5 AS seq
FROM week wk
INNER JOIN rotation_discipline_block rdb ON rdb.rotation_discipline_block_pk = wk.rotation_discipline_block_fk
INNER JOIN unit u ON u.unit_pk = rdb.unit_fk
INNER JOIN year y ON u.year_fk = y.year_pk
UNION ALL
SELECT
CONCAT('year:', year_fk, ',unit:', unit_name, ',rotation_discipline_block:', rotation_discipline_block_name, ',week:', week_name, ',learning_event:', learning_event_name) AS global_id,
learning_event_name AS name,
CONCAT('year:', year_fk, ',unit:', unit_name, ',rotation_discipline_block:', rotation_discipline_block_name, ',week:', week_name) AS parent_global_id,
6 AS seq
FROM learning_event le
INNER JOIN week wk ON wk.week_pk = le.week_fk
INNER JOIN rotation_discipline_block rdb ON rdb.rotation_discipline_block_pk = wk.rotation_discipline_block_fk
INNER JOIN unit u ON u.unit_pk = rdb.unit_fk
INNER JOIN year y ON u.year_fk = y.year_pk
ORDER BY seq ASC,
CASE seq
WHEN 1 THEN 0
WHEN 2 THEN CAST(SUBSTRING(name, 6) AS SIGNED)
WHEN 3 THEN CAST(SUBSTRING(name, -2) AS SIGNED)
WHEN 4 THEN 0
WHEN 5 THEN CAST(SUBSTRING(name, 6) AS SIGNED)
WHEN 6 THEN 0
END ASC,
name ASC
参见 db-fiddle
所以,回顾一下:
learning_event
表中记录的父项是EITHER 记录 在表week
OR 表rotation_discipline_block
中的记录。两者都不是。learning_event
表中记录的父级由 EITHERlearning_event.week_fk
OR 的值learning_event.rotation_discipline_block_fk
:如果
learning_event.week_fk
值 > 0 那么 parent 是week
表中week_pk
的对应值。否则,如果
learning_event.week_fk
值 == 0 那么 learning_event 记录是表rotation_discipline_block
中的匹配记录,如learning_event.rotation_discipline_block_fk
中所定义。在这种情况下,周不在 learning_event 记录的层次结构中。
这个问题开头的两个列表说明了这一点。
例如:
表learning_event
有两条记录:
(133, 'Antigen capture and processing', '', 0, 22),
(134, 'Antigen capture and presentation - MHC', '', 7, 0),
上面的第一条记录显示 week_fk 列为 0,rotation_discipline_block_fk
列为 22。因此,该记录的父项应该是表 rotation_discipline_block
中 rotation_discipline_block_pk
为 22 的记录。
上面的第二条记录显示 week_fk
为 7,因此该记录的父项应该是 week
表中带有 week_pk
的记录共 7 个。
最佳答案
使用 case
关于加入,
SELECT CONCAT('program:', program_pk) AS global_id,
program_name AS name,
NULL AS parent_global_id,
1 AS seq
FROM program
UNION ALL
SELECT CONCAT('year:', year_pk) AS global_id,
year_name AS name,
CONCAT('program:', program_fk) AS parent_global_id,
2 AS seq
FROM year
UNION ALL
SELECT
CONCAT('year:', year_fk, ',unit:', unit_name) AS global_id,
unit_name AS name,
CONCAT('year:', year_fk) AS parent_global_id,
3 AS seq
FROM unit
UNION ALL
SELECT
CONCAT('year:', year_fk, ',unit:', unit_name, ',rotation_discipline_block:', rotation_discipline_block_name) AS global_id,
rotation_discipline_block_name AS name,
CONCAT('year:', year_fk, ',unit:', unit_name) AS parent_global_id,
4 AS seq
FROM rotation_discipline_block rdb
INNER JOIN unit u ON u.unit_pk = rdb.unit_fk
UNION ALL
SELECT
CONCAT('year:', year_fk, ',unit:', unit_name, ',rotation_discipline_block:', rotation_discipline_block_name, ',week:', week_name) AS global_id,
week_name AS name,
CONCAT('year:', year_fk, ',unit:', unit_name, ',rotation_discipline_block:', rotation_discipline_block_name) AS parent_global_id,
5 AS seq
FROM week wk
INNER JOIN rotation_discipline_block rdb ON rdb.rotation_discipline_block_pk = wk.rotation_discipline_block_fk
INNER JOIN unit u ON u.unit_pk = rdb.unit_fk
INNER JOIN year y ON u.year_fk = y.year_pk
UNION ALL
SELECT
CONCAT('year:', year_fk, ',unit:', unit_name, ',rotation_discipline_block:', rotation_discipline_block_name, ',week:', week_name, ',learning_event:', learning_event_name) AS global_id,
learning_event_name AS name,
CONCAT('year:', year_fk, ',unit:', unit_name, ',rotation_discipline_block:', rotation_discipline_block_name, ',week:', week_name) AS parent_global_id,
6 AS seq
FROM year y
INNER JOIN unit u ON y.year_pk = u.year_fk
INNER JOIN rotation_discipline_block rdb ON u.unit_pk = rdb.unit_fk
INNER JOIN week wk ON rdb.rotation_discipline_block_pk = wk.rotation_discipline_block_fk
INNER JOIN learning_event le ON CASE WHEN le.week_fk = 0 THEN rdb.rotation_discipline_block_pk = le.rotation_discipline_block_fk ELSE wk.week_pk = le.week_fk END
ORDER BY seq ASC,
CASE seq
WHEN 1 THEN 0
WHEN 2 THEN CAST(SUBSTRING(name, 6) AS SIGNED)
WHEN 3 THEN CAST(SUBSTRING(name, -2) AS SIGNED)
WHEN 4 THEN 0
WHEN 5 THEN CAST(SUBSTRING(name, 6) AS SIGNED)
WHEN 6 THEN 0
END ASC,
name ASC
更新:
对于 seq = 6
更新:
你可以使用两个联合查询,所以 block 将是
#q1
SELECT
CONCAT('year:', year_fk, ',unit:', unit_name, ',rotation_discipline_block:', rotation_discipline_block_name, ',week:', week_name, ',learning_event:', learning_event_name) AS global_id,
lewk.learning_event_name AS name,
CONCAT('year:', year_fk, ',unit:', unit_name, ',rotation_discipline_block:', rotation_discipline_block_name, ',week:', week_name) AS parent_global_id,
6 AS seq
FROM year y
INNER JOIN unit u ON y.year_pk = u.year_fk
INNER JOIN rotation_discipline_block rdb ON u.unit_pk = rdb.unit_fk
INNER JOIN week wk ON rdb.rotation_discipline_block_pk = wk.rotation_discipline_block_fk
INNER JOIN learning_event lewk ON wk.week_pk = lewk.week_fk and lewk.week_fk <> 0
UNION ALL
#q2
SELECT
CONCAT('year:', year_fk, ',unit:', unit_name, ',rotation_discipline_block:', rotation_discipline_block_name, ',learning_event:', learning_event_name) AS global_id,
lerdb.learning_event_name AS name,
CONCAT('year:', year_fk, ',unit:', unit_name, ',rotation_discipline_block:', rotation_discipline_block_name) AS parent_global_id,
6 AS seq
FROM year y
INNER JOIN unit u ON y.year_pk = u.year_fk
INNER JOIN rotation_discipline_block rdb ON u.unit_pk = rdb.unit_fk
INNER JOIN learning_event lerdb ON rdb.rotation_discipline_block_pk = lerdb.rotation_discipline_block_fk AND lerdb.week_fk = 0;
所以工作结果将是db-fiddle
更新:
您还可以删除条件 lewk.week_fk <> 0
和 lerdb.week_fk = 0
来自 join
并且可以在 where 子句中使用。
关于MySQL - 如果第一个外键为空,如何处理使用第二个外键的情况?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/58177246/