Description

Table: Tasks

+----------------+---------+  
| Column Name    | Type    |  
+----------------+---------+  
| task_id        | int     |  
| subtasks_count | int     |  
+----------------+---------+  
task_id is the primary key for this table.  
Each row in this table indicates that task_id was divided into subtasks_count subtasks labeled from 1 to subtasks_count.  
It is guaranteed that 2 <= subtasks_count <= 20.

Table: Executed

+---------------+---------+  
| Column Name   | Type    |  
+---------------+---------+  
| task_id       | int     |  
| subtask_id    | int     |  
+---------------+---------+  
(task_id, subtask_id) is the primary key for this table.  
Each row in this table indicates that for the task task_id, the subtask with ID subtask_id was executed successfully.  
It is guaranteed that subtask_id <= subtasks_count for each task_id.

Write an SQL query to report the IDs of the missing subtasks for each task_id.

Return the result table in any order.

SQL Schema

Create table If Not Exists Tasks (task_id int, subtasks_count int)  
Create table If Not Exists Executed (task_id int, subtask_id int)  
Truncate table Tasks  
insert into Tasks (task_id, subtasks_count) values ('1', '3')  
insert into Tasks (task_id, subtasks_count) values ('2', '2')  
insert into Tasks (task_id, subtasks_count) values ('3', '4')  
Truncate table Executed  
insert into Executed (task_id, subtask_id) values ('1', '2')  
insert into Executed (task_id, subtask_id) values ('3', '1')  
insert into Executed (task_id, subtask_id) values ('3', '2')  
insert into Executed (task_id, subtask_id) values ('3', '3')  
insert into Executed (task_id, subtask_id) values ('3', '4')

Idea

The query result format is in the following example.

+---------+------------+  
| task_id | subtask_id |  
+---------+------------+  
| 1       | 1          |  
| 1       | 3          |  
| 2       | 1          |  
| 2       | 2          |  
+---------+------------+

Fulfill requirements :

Using the with recursive to generate a serial number for subtasks_id from 1 to 20, then finding not executed subtasks with condition ifnull(task_id) or ifnull(subtask_id) which subtask_id records not in table Executed.

Solution

with  
recursive cte_subtasks_sn as (  
    SELECT 1 AS subtask_id   
    UNION ALL   
    SELECT subtask_id + 1 FROM cte_subtasks_sn WHERE subtask_id < 20   
),  
cte_subtasks_count as (  
    select  
        a.task_id as task_id,  
        b.subtask_id as subtask_id  
    from Tasks a, cte_subtasks_sn b  
    where b.subtask_id <= a.subtasks_count  
)  
  
select  
    a.task_id, a.subtask_id  
from cte_subtasks_count a  
left join Executed b using(task_id, subtask_id)  
where ifnull(b.task_id, -1) = -1 or ifnull(b.subtask_id, -1) = -1  
order by task_id, subtask_id