SQL left self-join with WHERE clause dependencies between the two copies of the table

user984003 picture user984003 · Apr 26, 2012 · Viewed 15.2k times · Source

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.

Answer

MatBailie picture MatBailie · Apr 26, 2012

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

NECRO EDIT:

Although the above fixes the use of LEFT JOIN, I would suggest not using joins at all...

SELECT
  sentence_id,
  MAX(CASE WHEN pos = 0 THEN word END)   AS word1,
  MAX(CASE WHEN pos = 1 THEN word END)   AS word2
FROM
(
  SELECT
    sentence_id,
    word_number - MY_START_NUMBER   AS pos,
    word
  FROM
    sentence_words
)
  AS offset_sentence_words
WHERE
  pos IN (0, 1)
GROUP BY
  sentence_id