Как использовать «NOT IN» в запросе?

Каков правильный способ написать запрос, содержащий «NOT IN», используя оператор условия?

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

  SELECT DISTINCT nid FROM node WHERE language NOT IN
  (Выберите язык
    FROM языки WHERE language = 'ab');
 

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

  $ query-> условие ('n.'. $ key, $ value, 'not in (выберите язык из
  языки, на которых язык = $ value) ');
 
26 голосов | спросил JurgenR 29 ThuEurope/Moscow2011-12-29T17:52:29+04:00Europe/Moscow12bEurope/MoscowThu, 29 Dec 2011 17:52:29 +0400 2011, 17:52:29

5 ответов


38

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

  $ query-> условие ('n.language', 'ab', '& gt;');
 

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

  • «NOT IN» принимается как оператор из SelectQuery :: condition () . Фактически, следующий запрос будет выполнен:

      $ query = db_select ('node', 'n') -> fields ('n');
    $ query-> условие ('n.nid', массив (1, 2, 3), 'NOT IN');
    $ nodes = $ query-> execute ();
    
    foreach ($ nodes as $ node) {
      ДСМ ($ node- & GT; NID);
    }
     
  • Как сообщается в условных предложениях («Subselects»), SelectQuery: : condition () принимает также объект, реализующий SelectQueryInterface как значение для $ value , например, возвращаемый db_select () ; проблема в том, что на самом деле вы можете просто использовать его, когда значение $ operator равно "IN" . См. Subselects не работают в условиях DBTNG, кроме случаев, когда они используются как значение для IN .

Единственный способ, с помощью которого я могу использовать оператор «NOT IN» с подзапросом в condition , - это:

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

      $ query-> условие ($ key, $ subquery_result, 'NOT IN');
     

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

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

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

  $ query = db_select ('node', 'n') -> extend ('PagerDefault');
  $ nids = $ query
  -> fields ('n', array ('nid', 'sticky', 'created'))
    -> условие («тип», «блог»)
    -> условие ('статус', 1)
    -> orderBy («липкий», «DESC»)
    -> orderBy ('created', 'DESC')
    -> limit (variable_get ('default_nodes_main', 10))
    - & GT; addTag ( 'node_access')
    - & GT; выполнить ()
    - & GT; fetchCol ();
 

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

  $ select = db_select ('node', 'n')
  -> поля ('n', array ('title'))
  -> условие ('n.nid', $ node-> book ['bid'])
  - & GT; addTag ( 'node_access');
$ title = $ select-> execute () -> fetchField ();
 
ответил kiamlaluno 29 ThuEurope/Moscow2011-12-29T20:31:36+04:00Europe/Moscow12bEurope/MoscowThu, 29 Dec 2011 20:31:36 +0400 2011, 20:31:36
3

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

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

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

  SELECT nid
FROM node n INNER JOIN Языки l ON n.language = l.language
WHERE язык NOT IN ('ab')
 

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

ответил tostinni 29 ThuEurope/Moscow2011-12-29T20:30:38+04:00Europe/Moscow12bEurope/MoscowThu, 29 Dec 2011 20:30:38 +0400 2011, 20:30:38
2

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

Пример:

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

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

ответил Berdir 30 FriEurope/Moscow2011-12-30T12:18:39+04:00Europe/Moscow12bEurope/MoscowFri, 30 Dec 2011 12:18:39 +0400 2011, 12:18:39
0

Более простой способ использования db_select с подзапросом NOT IN состоит в том, чтобы использовать малоизвестный

$ query-> ; где

, чтобы добавить произвольное условие.

например:

  //Считать запрос для пользователей без удаления 3
  $ query = db_select ('users', 'u');
  $ query-> поля ('u', array ('uid'));
  $ query-> где ('u.uid NOT IN (выберите uid из {users_roles}, где rid =: rid)', array (': rid' => 3));
  $ count = $ query-> countQuery () -> execute () -> fetchField ();
  drupal_set_message ($ кол);
 
ответил David Thomas 10 Mayam13 2013, 03:13:40
0

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

  $ query-> условие ('node.nid', array_values ​​($ subquery_values), "NOT IN");
 

он отлично работает.

ответил Riccardo Ravaro 30 Maypm15 2015, 20:19:00

Похожие вопросы

Популярные теги

security × 330linux × 316macos × 2827 × 268performance × 244command-line × 241sql-server × 235joomla-3.x × 222java × 189c++ × 186windows × 180cisco × 168bash × 158c# × 142gmail × 139arduino-uno × 139javascript × 134ssh × 133seo × 132mysql × 132