Два соединения в запросе mysql не возвращают ожидаемый результат

Я работаю над соединением и не могу получить нужный мне набор результатов. Нарисую сценарий:

У меня есть 2 таблицы:

Таблица данных

+----+-------+
| ID | Name  |
+----+-------+
| 10 | Test1 |
| 11 | Test2 |
| 12 | Test3 |
| 13 | Test4 |
| 14 | Test5 |
| 15 | Test6 |
+----+-------+

Присоединиться к столу

+----+-----+-----+-----+
| ID | FID | GID | Val |
+----+-----+-----+-----+
| 10 |   3 |     | abc |
| 10 |     |   1 | def |
| 11 |   3 |     | ijk |
| 12 |     |   1 | lmn |
| 13 |   4 |     | opq |
+----+-----+-----+-----+

Ожидаемый набор результатов

+---------------+-----------------+---------------+----------------+----------------+
| Data table id | Data table name | Join Tabe FID | Join Table GID | Join Table Val |
+---------------+-----------------+---------------+----------------+----------------+
|            10 | Test1           |             3 |                | abc            |
|            11 | test2           |             3 |                | ijk            |
|            12 | test3           |               |              1 | lmn            |
+---------------+-----------------+---------------+----------------+----------------+

Мой запрос

Select
   *
from
   datatable A
join jointable b
on
   A.ID = B.ID
   and B.FID = 3
join jointable c
on
   A.ID = C.ID
   and C.GID = 1
   and C.FID <> null

Что происходит, так это то, что соединение таблицы C выполняется для набора результатов соединения между таблицами A и B, поэтому набор результатов пуст.

Я хочу, чтобы соединение таблицы C применялось к таблице A, а не к набору результатов соединения между таблицами A и B; что приведет к ожидаемому набору результатов.

Кто-нибудь может помочь?

Спасибо


person Yash    schedule 15.03.2016    source источник
comment
Нет записей с id равным 3, поэтому я ожидаю, что B.ID = 3 отфильтрует все записи.   -  person Gordon Linoff    schedule 15.03.2016
comment
Я думаю, что вам нужно левое внешнее соединение, но я не совсем понимаю ваш вопрос.   -  person mh-dev    schedule 15.03.2016
comment
@GordonLinoff Извините, опечатка, исправил   -  person Yash    schedule 15.03.2016
comment
@mh-dev левое внешнее соединение вернет идентификатор 13, который мне не нужен   -  person Yash    schedule 15.03.2016
comment
кто-нибудь может объяснить, чего хочет ОП? Я не понимаю этого от бывшего.   -  person Zahiro Mor    schedule 15.03.2016
comment
@ZahiroMor проверьте ответ Spencer7593: stackoverflow.com/a/36014355/439002 . Может быть, это поможет понять, что мне нужно   -  person Yash    schedule 15.03.2016


Ответы (5)


Выражение C.FID <> null никогда не будет оцениваться как истинное, оно всегда будет возвращать NULL. Сравнение неравенства с NULL всегда дает NULL. (В SQL, в логическом контексте, выражение en оценивается как одно из трех возможных значений: TRUE, FALSE или NULL.)

Если вы хотите, чтобы сравнение с NULL возвращало TRUE или FALSE, используйте тест сравнения IS [NOT] NULL. Выражение вроде

foo IS NULL

or

foo IS NOT NULL

Или вы можете использовать специфичный для MySQL оператор сравнения (космический корабль) с нулевой безопасностью:

foo <=> NULL

or

NOT (foo <=> NULL)

Что касается результата, который вы хотите вернуть, это немного сбивает с толку, как вы приходите к тому, что хотите вернуть.

Мне кажется, что вы хотите получить совпадающие строки из jointable... если есть совпадающие строки с fid=3, верните только эти строки. Если совпадающих строк с fid=3 нет, возвращаются строки со значением NULL в fid и gid=1.

Если это то, что мы хотим вернуть, мы можем написать запрос, который делает это. Если это не то, что мы хотим вернуть, то остальная часть этого ответа не имеет значения.

Мы можем использовать предикат NOT EXISTS для проверки отсутствия совпадающих строк.

Например:

SELECT d.id 
     , d.name
     , j.fid
     , j.gid
     , j.val
  FROM datatable d
  JOIN jointable j
    ON j.id = d.id
 WHERE ( j.fid = 3 )
    OR ( j.fid IS NULL
         AND j.gid = 1 
         AND NOT EXISTS ( SELECT 1
                            FROM jointable t
                           WHERE t.id = d.id
                             AND t.fid = 3
                        )
       )
person spencer7593    schedule 15.03.2016

SELECT
*
FROM datatable A
LEFT JOIN jointable B ON A.ID = B.ID 
WHERE B.FID = 3 OR B.GID = 1;

Это вернет вам:

10  Test1   10  3       abc
10  Test1   10      1   def
11  Test2   11  3       ijk
12  Test3   12      1   lmn

Теперь, кажется, вы хотите отфильтровать:

10  Test1   10  3       abc

и хранить

10  Test1   10      1   def

Это то, что вы хотите?

С уважением

person White Feather    schedule 15.03.2016
comment
Левое СОЕДИНЕНИЕ здесь не нужно, ГДЕ B превращает его во ВНУТРЕННЕЕ СОЕДИНЕНИЕ - person Mihai; 15.03.2016

SELECT *
FROM   table1 a
INNER JOIN table2 b ON a.ID = b.ID
WHERE b.FID = 3 OR b.GID = 1

Но ваш вопрос не очень конкретен в отношении предложений WHERE.

person L Kefalas    schedule 15.03.2016

SELECT * FROM db1 
INNER JOIN db2 ON db1.id = db2.id
WHERE db1.FID = 3 or db2.GID = 1;

Почему вы используете C.FID ‹> null, когда B.GID = 1? Он должен быть нулевым.

person Justinas Jakavonis    schedule 15.03.2016

Честно говоря, не уверен, понимаю ли я, что вы хотите, так что это может быть неправильно. Я думаю, что вы хотите. У вас есть две таблицы, и вы хотите объединить все строки из таблицы соединений, в которых совпадает идентификатор и fid= 3 или gid=1 и fid не равно null. Запрос для этого должен быть примерно таким. (одного соединения должно быть достаточно)

Select
   *
from
   datatable A
join jointable b
on
   A.ID = B.ID
where b.fid = 3 or (b.gid = 1 and b.fid <> null)
person mh-dev    schedule 15.03.2016