MySQL - 如果第一个外键为空,如何处理使用第二个外键的情况?

标签 mysql sql

我有一个查询,它从如下表中生成分层结果:

  • 程序
      • 单位
        • 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
          • 学习事件

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 ORrotation_discipline_block 中的记录。两者都不是。

  • learning_event 表中记录的父级由 EITHER learning_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_blockrotation_discipline_block_pk 为 22 的记录。

上面的第二条记录显示 week_fk 为 7,因此该记录的父项应该是 week 表中带有 week_pk 的记录共 7 个。

请参阅 Updated db-fiddle

最佳答案

使用 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 <> 0lerdb.week_fk = 0来自 join并且可以在 where 子句中使用。

关于MySQL - 如果第一个外键为空,如何处理使用第二个外键的情况?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/58177246/

相关文章:

php - 为什么我没有为 header 显示不同的 PHP 日期值?

mysql - mysql 的 Powershell 代码不工作

php - 使用 2 GROUP_CONCAT 安全吗?

MySQL 代码到 postgres

sql - 找出谁修改了存储过程

php - 在 SQL 中选择具有最高值的列

php - 想要从 MySQL 表创建比较矩阵

MySQL- 平均 15 分钟间隔

mysql - 如何根据同一个表的先前搜索结果更新SQL列

sql - 甲骨文 ORA-00600