Звучит так, будто вы хотите сделать LEFT JOIN
, а затем проверить результаты, в которых значение объединенной таблицы равно NULL
, указывая, что такой объединенной записи не существует.
Например:
SELECT * FROM posts
LEFT JOIN metadata ON (posts.pid = metadata.pid AND metadata.k = 'optout')
WHERE metadata.mdid IS NULL;
Это выберет любую строку из таблицы posts
, для которой не существует соответствующей строки metadata
со значением k = 'optout'
.
edit: Стоит отметить, что это ключевое свойство левого соединения и не будет работать с обычным соединением; левое соединение всегда будет возвращать значения из первой таблицы, даже если в объединенной таблице (таблицах) не найдено соответствующих значений, что позволяет выполнять выборки на основе отсутствия этих строк.
edit 2: Давайте проясним, что здесь происходит в отношении LEFT JOIN
против JOIN
(для ясности я называю INNER JOIN
, но взаимозаменяемы в MySQL).
Предположим, вы выполняете любой из этих двух запросов:
SELECT posts.*, metadata.mdid, metadata.k, metadata.v
FROM posts
INNER JOIN metadata ON posts.pid = metadata.pid;
или
SELECT posts.*, metadata.mdid, metadata.k, metadata.v
FROM posts
LEFT JOIN metadata ON posts.pid = metadata.pid;
Оба запроса выдают следующий набор результатов:
+-----+-------+--------------+------+-------+-----------+
| pid | title | content | mdid | k | v |
+-----+-------+--------------+------+-------+-----------+
| 1 | Foo | Some content | 1 | date | yesterday |
| 1 | Foo | Some content | 2 | thumb | img.jpg |
+-----+-------+--------------+------+-------+-----------+
Теперь давайте предположим, что мы изменили запрос, чтобы добавить дополнительные критерии для "отказа", которые были упомянуты. Во-первых, INNER JOIN
:
SELECT posts.*, metadata.mdid, metadata.k, metadata.v
FROM posts
INNER JOIN metadata ON (posts.pid = metadata.pid AND metadata.k = "optout");
Как и ожидалось, это не даст результатов:
Empty set (0.00 sec)
Теперь, изменив это на LEFT JOIN
:
SELECT posts.*, metadata.mdid, metadata.k, metadata.v
FROM posts
LEFT JOIN metadata ON (posts.pid = metadata.pid AND metadata.k = "optout");
Это создает результат:
+-----+-------+--------------+------+------+------+
| pid | title | content | mdid | k | v |
+-----+-------+--------------+------+------+------+
| 1 | Foo | Some content | NULL | NULL | NULL |
+-----+-------+--------------+------+------+------+
Разница между INNER JOIN
и LEFT JOIN
заключается в том, что INNER JOIN
вернет результат, только если строки из ОБА соединенных таблиц совпадают. В LEFT JOIN
соответствующие строки из первой таблицы будут ВСЕГДА возвращаться независимо от того, найдено ли что-либо для соединения. Во многих случаях не имеет значения, какой из них вы используете, но важно выбрать правильный, чтобы не получить неожиданные результаты в будущем.
Так что в этом случае предложенный запрос:
SELECT posts.*, metadata.mdid, metadata.k, metadata.v
LEFT JOIN metadata ON (posts.pid = metadata.pid AND metadata.k = 'optout')
WHERE metadata.mdid IS NULL;
Вернет тот же набор результатов, что и выше:
+-----+-------+--------------+------+------+------+
| pid | title | content | mdid | k | v |
+-----+-------+--------------+------+------+------+
| 1 | Foo | Some content | NULL | NULL | NULL |
+-----+-------+--------------+------+------+------+
Надеюсь, это прояснит ситуацию! Объединение - это отличная вещь для изучения, так как у нее есть полное понимание того, когда использовать, и это очень хорошая вещь.