sqlsqliteselect

Get all non-empty rows from one column and then get all matching rows for those values


I've built a program that converts an Excel sheet containing my departments schedule to a SQL table. We always work in pairs so I want to be able to check all my shifts and what person I'll be working with for those shifts.
Table structure is, where T, K and N are the different shifts:

Week Date Jim Chad Ernest Rogier
10 2025-04-14 T K N T
10 2025-04-15 K K N T
10 2025-04-16 N K N T
10 2025-04-17 N K N T

If I'm Jim in the table above I want to be able to get a response for 2025-04-14 like:

Week Date Jim Rogier
10 2025-04-14 T T

And for 2025-04-15 like:

Week Date Jim Chad
10 2025-04-15 K K

I honestly have no idea how to do something like this. I've only done very basic SQL queries before, like finding all rows where the X equals Y.


Solution

  • SQL isn't really geared to dynamically handling columns.

    One approach suggested in the comments is to show nulls for the people that don't share a shift with Jim, using a case expression

    SELECT week, date, jim,
           CASE chad WHEN jim THEN chad END,
           CASE ernest WHEN jim THEN ernest END,
           CASE rogier WHEN jim THEN rogier END
    FROM   shifts
    

    A slightly nicer (IMHO) solution is to use a case expression to display the name of the person sharing a shift with Jim:

    SELECT week, date, jim,
           CASE jim 
                WHEN chad THEN 'Chad'
                WHEN ernest THEN 'Ernest'
                WHEN rogier THEN 'Rogier'
           END
    FROM   shifts
    

    But ultimately, both of these are workarounds for a table design that isn't sufficiently normalized.
    A more idiomatic approach would be to have a row in the table for each person's shift (i.e., your columns would be week, date, shift and name), and then self-join the table:

    SELECT j.week, j.date, j.shift, o.name AS who_is_with_jim
    FROM   shifts j
    LEFT JOIN shifts o ON j.week = o.week AND
                          j.date = o.date AND
                          j.shift = o.shift AND
                          j.name = 'Jim' AND
                          o.name != 'Jim'