Search code examples
mysqlcomplement

Mysql complement with many tables and grouping


I hope the answer is simple and I'm silly.

So I've two tables: day (with PK id_day) and hour (with PK id_hour).

I've an another table tilt_time which has id_day, id_hour fields and a plus FK field (which has prohibited times). E.g. tilt_time has the following rows (id_day, id_hour, id_target):

1,1,1
1,2,1
1,3,1
1,1,2
1,2,2

In table day id_day is between 1 and 5 (monday to friday) and hour id_hour is between 1 and 6 (so you can imagine a day_hour table with 5*6=30 values).

So I want query id_target=1's free periods and id_target=2's free periods (everbody's free periods). So I want similar:

1,4,1
1,5,1
1,6,1
2,*,1
3,*,1
4,*,1
5,*,1
// id_target=2
1,3,2
1,4,2
1,5,2
1,6,2
2,*,2
3,*,2
4,*,2
5,*,2

(* means all valid id_hour values, so every line with * represents 6 different lines)

How can I do this query?


Solution

  • If you have a target table with all id_target, the answer is simple:

    SELECT 
        d.id_day, h.id_hour, t.id_target
    FROM 
        day AS d
      CROSS JOIN
        hour AS h
      CROSS JOIN
        target AS t
    WHERE
        (d.id_day, h.id_hour, t.id_target) NOT IN
          ( SELECT id_day, id_hour, id_target
            FROM tilt_time
          )
    ;
    

    or the (probably more efficient):

    SELECT 
        d.id_day, h.id_hour, t.id_target
    FROM 
        day AS d
      CROSS JOIN
        hour AS h
      CROSS JOIN
        target AS t
      LEFT JOIN
        tilt_time AS tt
          ON  tt.id         = d.id_day
          AND tt.id_hour    = h.id_hour
          AND t.t.id_target = t.id_target
    WHERE 
        tt.id_target iS NULL ;
    

    If you don't have a target table, replace the target AS t in the code above with:

    ( SELECT DISTINCT id_target FROM tilt_time ) AS t