SQL left self-join with WHERE clause dependencies

2020-08-23 06:42发布

问题:

The following two sentences:

hello there
bye!

are represented in the table sentence_words by:

WORD_ID  SENTENCE_ID    WORD    WORD_NUMBER
10       1              hello   1
11       1              there   2
12       2              bye!    1

I want to do an outer join query that gives me the results:

WORD1      WORD2
hello      there
bye!       NULL

Note that I may want to start in the middle of the sentence so I cannot assume that word2 has word_number = 2. If I choose my_start_number = 2 then the query should give me:

WORD1   WORD2
there   NULL

I tried:

(my_start_number = 1)

select  s1.word word1, s2.word word2
from sentence_words s1
left join sentence_words s2
on s1.sentence_id = s2.sentence_id
where s1.word_number = my_start_number
 and (s2.word_number = s1.word_number +1 or s2.word_number is null);

That only gives me a result if there are two words in the sentence. I'm not sure what to do that isn't way complicated.

回答1:

Move the word_number + 1 requirement into the LEFT JOIN.

SELECT
  s1.word word1, s2.word word2
FROM
  sentence_words s1
LEFT JOIN
  sentence_words s2
    ON  s2.sentence_id = s1.sentence_id
    AND s2.word_number = s1.word_number + 1
WHERE
  s1.word_number = my_start_number


回答2:

Dems answer is absolutely the correct one. I decided to write this answer to explain the reason that your original solution doesn't work. This is because you are trying to filter the following result set of the left outter join (showing all columns, with some names abbreviated to fit):

s1.WORD_ID s1.SENT_ID s1.WORD  s1.WORD_NUM s2.WORD_ID s2.SENT_ID s2.WORD  s2.WORD_NUM
10         1          hello    1           10         1          hello    1
10         1          hello    1           11         1          there    2
11         1          there    2           10         1          hello    1
11         1          there    2           11         1          there    2
12         2          bye!     1           12         2          bye!     1

Now, take a look at your where clause:

where s1.word_number = my_start_number  
 and (s2.word_number = s1.word_number +1 or s2.word_number is null);  

... and it should be relatively easy to see why it doesn't work. For example, s2.word_number is never NULL.