Как мне использовать "НЕ В" в запросе?


Как правильно написать запрос, содержащий "НЕ В", используя оператор условия?

Мой запрос следующий:

SELECT DISTINCT nid FROM node WHERE language NOT IN 
  (SELECT language 
    FROM languages WHERE language = 'ab');

Я пробовал что-то вроде следующего:

$query->condition('n.' . $key, $value, 'not in (select language from 
  languages where language = $value)');
 27
Author: tostinni, 2011-12-29

5 answers

В конкретном примере вы должны просто записать условие как:

$query->condition('n.language', 'ab', '<>');

В общем случае, когда вам нужно выбрать строки в базе данных на основе значений, возвращаемых из подзапроса, вам следует рассмотреть следующее:

Единственный способ, который я вижу, чтобы использовать оператор "НЕ В" с подзапросом в condition, это:

  • Выполните подзапрос, чтобы получить массив
  • Выполните основной запрос, задав условие, как в следующий фрагмент

    $query->condition($key, $subquery_result, 'NOT IN');
    

    $subquery_result является массивом, содержащим результат подзапроса.

В противном случае вы можете использовать where(), как говорили другие, который принимает строку для той части запроса, которую вам нужно добавить.

Имейте в виду, что db_select() медленнее, чем db_query(); вы должны использовать первый, когда знаете, что запрос может быть изменен другими модулями. В противном случае, если другие модули не должны использовать hook_query_alter() для изменения вашего запроса, вам следует использовать db_query().
В в случае доступа к узлам, если вам нужно получить только те узлы, к которым у пользователя есть доступ, вам нужно использовать db_select() и добавить 'node_access' в качестве тега запроса, с SelectQuery::addTag(). Например, blog_page_last() использует следующий код.

  $query = db_select('node', 'n')->extend('PagerDefault');
  $nids = $query
  ->fields('n', array('nid', 'sticky', 'created'))
    ->condition('type', 'blog')
    ->condition('status', 1)
    ->orderBy('sticky', 'DESC')
    ->orderBy('created', 'DESC')
    ->limit(variable_get('default_nodes_main', 10))
    ->addTag('node_access')
    ->execute()
    ->fetchCol();

Аналогичный код используется book_block_view().

$select = db_select('node', 'n')
  ->fields('n', array('title'))
  ->condition('n.nid', $node->book['bid'])
  ->addTag('node_access');
$title = $select->execute()->fetchField();
 42
Author: kiamlaluno, 2016-11-10 17:16:18

При написании сложных запросов вам обязательно следует использовать db_query() вместо того, чтобы db_select().

  1. Вы не можете написать предложение NOT IN с подзапросом с текущим API базы данных Drupal (это известная проблема , которая разрабатывается).
  2. Если вам не нужно, чтобы ваш запрос был динамическим (следовательно, переписанным другими модулями), не беспокойтесь , пытаясь написать такой сложный с db_select().
  3. Подзапросы еще недостаточно поддерживаются (см. мой предыдущий ответ ), и если вы привыкли писать SQL, его намного проще использовать db_query().

Что касается вашего запроса, я не уверен, почему вы хотите использовать подзапрос (если только вы не упростили свой пример)? Вы можете легко написать это так:

SELECT nid 
FROM node n INNER JOIN languages l ON n.language = l.language
WHERE language NOT IN ('ab')

DISTINCT не обязательно, так как nid является первичным ключом, поэтому он не будет дублироваться.

 5
Author: tostinni, 2017-04-13 12:47:11

Также есть where(), который позволяет добавить в запрос произвольное условие where.

Пример:

$query->where('n.language NOT IN (SELECT language FROMlanguages WHERE language = :lang)', array(':lang' => $value));

Как упоминал Кейтм, вы должны использовать db_select() и addTag('node_access') при выборе узлов, которые затем отображаются пользователям.

 3
Author: Berdir, 2011-12-30 08:18:39

Более простой способ использовать db_select с НЕ В подвыборке - это просто использовать малоизвестный

$ запрос->где

Для добавления произвольного условия where.

Например:

  // Count query for users without rid 3
  $query = db_select('users', 'u');
  $query->fields('u', array('uid'));
  $query->where('u.uid NOT IN(select uid from {users_roles} where rid = :rid)', array(':rid' => 3));  
  $count = $query->countQuery()->execute()->fetchField();
  drupal_set_message($count);
 2
Author: David Thomas, 2013-05-09 23:13:40

Где $subquery_values - это массив формата $key => $nid в результате подзапроса

$query->condition('node.nid', array_values($subquery_values), "NOT IN");

Это прекрасно работает.

 1
Author: Riccardo Ravaro, 2015-05-30 17:19:00