Search code examples
sqlnullsubquery

Subquery with multiple columns and possible null returned (SQL)


I have a few tables that i need to extract informations from, but i feel like the way i do this can be optimized. The context is a player gives an information to another player. Those informations are lore elements of a game, and thus already defined in a table "knlist". Who gave what info is stored in a table "knlogs".

So when a player wants to give an information to another player, it needs first to see if this player already has it. So what i want is the list of all this player's knowledge, with additional columns saying if there is already a log of the other player having it. That would be simple enough with a subquery, but right after i need another information from this possible log, so a second column in the subquery. And here, i can't join the tables because it is entirely possible that the log simply doesn't exist. I need to have a null returned in the columns.

Here is how i made this for now. The problem is that i have two subqueries that access the exact same row, if it exist.

Tables : Note that there are more columns in each one of them, but for the sake of simplicity ...

knlist                                | knlogs
                                      |
idknowledge        description        | idknowledge        idlearner          dateknowledge      datetheory
----------------   ----------------   | ----------------   ----------------   ----------------   ----------------
1                  Some text.         | 1                  6166               2020-08-07         0000-00-00
2                  Some more text.    | 2                  6166               2020-08-07         0000-00-00
3                  Sample data.       | 1                  3069               2020-08-01         0000-00-00
4                  Even more text.    | 3                  3069               0000-00-00         2019-12-31

Let's assume the user 6166 wants to give some info to user 3069. I want to see if 3069 already has the information, or a theory of it.

SELECT li.description, li.idknowledge,
  (SELECT datetheory FROM knlogs where idknowledge=li.idknowledge and idlearner=3092) as datetheory_user_2,
  (SELECT dateknowledge FROM knlogs where idknowledge=li.idknowledge and idlearner=3092) AS dateknowledge_user_2
FROM knlist as li, knlogs as lo
WHERE li.idknowledge=lo.idknowledge and lo.idlearner=6166

This is what i have, and it works. It returns :

description        idknowledge        datetheory_user_2         dateknowledge_user_2
----------------   ----------------   -----------------------   -----------------------
Some text.         1                  0000-00-00                2020-08-01                
Some more text.    2                  NULL                      NULL

Now the request contains the same subquery, just on two different columns. I figured i can't join with another table selected in the FROM section, because of the possible NULL. If i were to do this, i would skip the second line returned.

Does anyone have a good alternative to this ? Thank you.


Solution

  • Never use commas in the FROM clause. Always use proper, explicit, standard, readable JOIN syntax.

    If you are trying to avoid subqueries, just use left join:

    SELECT li.description, li.idknowledge,
           lo2.datetheory as datetheory_user_2,
           lo2.dateknowledge as dateknowledge_user_2
    FROM knlist li join
         knlogs lo
         on li.idknowledge = lo.idknowledge left join
         knlogs lo2
         on lo2.idknowledge = lo.idknowledge and
            lo2.idlearner = 3092
    WHERE lo.idlearner = 6166;