쿼리에서 "NOT IN"을 어떻게 사용합니까?


26

조건문을 사용하여 'NOT IN'을 포함하는 쿼리를 작성하는 올바른 방법은 무엇입니까?

내 쿼리는 다음과 같습니다.

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)');

어쩌면 나는 명백한 것을 놓치고 있지만 쿼리와 SELECT nid FROM node WHERE language != 'ab'? 의 차이점은 무엇 입니까?
Елин Й.

답변:


38

구체적인 예에서는 다음과 같이 조건을 작성해야합니다.

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

하위 쿼리에서 반환 된 값을 기준으로 데이터베이스에서 행을 선택해야하는 일반적인 경우 다음 사항을 고려해야합니다.

  • 의 연산자로 "NOT IN"이 허용됩니다 SelectQuery::condition(). 실제로 다음 쿼리가 실행됩니다.

    $query = db_select('node', 'n')->fields('n');
    $query->condition('n.nid', array(1, 2, 3), 'NOT IN');
    $nodes = $query->execute();
    
    foreach ($nodes as $node) {
      dsm($node->nid);
    }
  • 조건절 ( "하위 선택") 에보고 된대로 ;에 의해 반환 된 것과 같은 값을 SelectQuery::condition()구현하는 객체도 허용 합니다 . 문제는의 값 이 같을 때 실제로 사용할 수 있다는 것 입니다. IN 값으로 사용되는 경우를 제외하고 DBTNG 조건에서 부속 선택이 작동하지 않음을 참조하십시오 .SelectQueryInterface$valuedb_select()$operator"IN"

하위 쿼리와 함께 "NOT IN"연산자를 사용하는 유일한 방법 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();

다음은 내가 작성한 뷰 사용자 정의 필터에 대한 하위 쿼리의 예입니다. link
Roger

1
"DIN은 DBTNG 조건에서 작동하지 않습니다. IN 값으로 사용될 때를 제외하고는"Drupal 8.3
Jonathan

3

복잡한 쿼리를 작성할 때는 반드시 사용해야합니다 db_query() 대신 대신 합니다 db_select().

  1. NOT IN현재 Drupal 데이터베이스 API를 사용하여 하위 쿼리로 절을 작성할 수 없습니다 (알려진 문제입니다 ).
  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')

DISTINCTnid기본 키는 필요 하지 않으므로 복제되지 않습니다.


2
# 2와 관련하여 OP는 노드를 선택합니다. AFAIK db_select ()는 필요한 'node_access'태그를 제공하는 유일한 방법이며,이 경우 db_select ()가 유일한 선택입니다.
keithm

2

또한 where ()쿼리에 임의의 where 조건을 추가 할 수 있습니다.

예:

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

keithm이 언급했듯이 노드를 선택할 때 db_select () 및 addTag ( 'node_access')를 사용해야 사용자에게 표시됩니다.


1

NOT IN 부속 선택과 함께 db_select를 사용하는 더 쉬운 방법은 알려진 것이 거의없는 것입니다.

$ query-> where

임의의 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);

0

여기서 $ subquery_values는 하위 쿼리의 결과로 $ key => $ nid 형식의 배열입니다.

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

잘 작동합니다.

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.