Bir sorguda “NOT IN” i nasıl kullanırım?


26

Condition deyimi kullanarak 'NOT IN' içeren bir sorgu yazmanın doğru yolu nedir?

Benim sorgum şudur:

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

Aşağıdaki gibi bir şey denedim:

$query->condition('n.' . $key, $value, 'not in (select language from 
  languages where language = $value)');

Belki de bariz olanı özlüyorum, ancak sorgunuzla arasındaki fark SELECT nid FROM node WHERE language != 'ab'nedir?
Елин Й.

Yanıtlar:


38

Belirli bir örnekte, durumu basitçe şöyle yazmalısınız:

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

Bir alt sorgudan döndürülen değerleri temel alan bir veritabanındaki satırları seçmeniz gereken genel durumda, aşağıdakileri göz önünde bulundurmalısınız:

  • "NOT IN", operatör olarak kabul edildi SelectQuery::condition(). Aslında, aşağıdaki sorgu yürütülür:

    $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);
    }
  • Koşullu fıkralarda ("Subselects") bildirildiği gibi , SelectQuery::condition()aynı zamanda tarafından döndürülenler SelectQueryInterfaceiçin değer olarak uygulayan bir nesneyi de kabul eder ; Buradaki sorun aslında değeri sadece eşit olduğunda kullanabilirsiniz . Bkz subselects IN değeri olarak kullanıldığı durumlar dışında, DBTNG koşullarda çalışmayı yok .$valuedb_select()$operator"IN"

Alt sorguda "NOT IN" işlecini kullanabilmenin tek yolu conditionşudur:

  • Bir dizi almak için alt sorguyu yürütün
  • Aşağıdaki pasajda olduğu gibi koşulu ayarlayan ana sorguyu yürütün

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

    $subquery_result alt sorgunun sonucunu içeren dizidir.

Aksi takdirde, where()başkalarının söylediği gibi kullanabilirsiniz ; bu, sorgunun eklemeniz gereken kısmı için bir dize kabul eder.

Bunun db_select()daha yavaş olduğunu unutmayın db_query(); Sorgunun diğer modüller tarafından değiştirilebileceğini bildiğiniz zaman ilkini kullanmalısınız. Aksi halde, hook_query_alter()sorgunuzu değiştirmek için diğer modüllerin kullanılması gerekmiyorsa, kullanmanız gerekir db_query().
Düğümlere erişme durumunda, yalnızca kullanıcının erişebildiği düğümleri edinmeniz gerekiyorsa , sorgunun etiketi olarak kullanmanız db_select()ve eklemeniz gerekir . Örneğin , aşağıdaki kodu kullanır.'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();

Benzer kod tarafından kullanılır 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();

İşte yazdığım bir özel filtre görünümüne ilişkin alt sorgu örneği: link
Roger

1
Drupal 8.3
Jonathan

3

Karmaşık sorgular yazarken db_query()yerine kesinlikle kullanmalısınız db_select().

  1. NOT INGeçerli Drupal veritabanı API'si olan bir alt sorguyla bir cümle yazamazsınız (bu, çözülmesi gereken bir sorun ).
  2. Sorgunuzun dinamik olması gerekiyorsa (bu nedenle başka modüller tarafından yeniden yazılmıştır), böyle bir karmaşık olanı yazmaya çalışarak zahmet etmeyindb_select() .
  3. Alt sorgular henüz iyi desteklenmedi ( önceki cevabımın cevabına bakınız ) ve SQL yazmaya alışkınsanız kullanımı çok daha kolay db_query().

Sorgunuzla ilgili olarak, neden bir alt sorgu kullanmak istediğinizden emin değilim (örneklemenizi basitleştirmediyseniz)? Kolayca bu şekilde yazabilirsiniz:

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

DISTINCTnidBirincil anahtar olduğu için gerekli olmadığından çoğaltılmayacaktır.


2
# 2 ile ilgili olarak, OP düğümleri seçiyor. AFAIK db_select (), gerekli herhangi bir 'node_access' etiketini sağlamanın tek yoludur, bu durumda db_select () tek seçenek olacaktır.
keithm

2

Sorguya koşul nerede bir koşul eklemenizi sağlayan where () de vardır .

Örnek:

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

Keithm de belirtildiği gibi, daha sonra kullanıcılara gösterilen düğümleri seçerken db_select () ve addTag ('node_access') kullanmanız gerekir.


1

Db_select'i NOT IN alt seçimiyle kullanmanın daha kolay bir yolu az bilinenleri kullanmaktır

$ Query-> nerede

İsteğe bağlı bir yeri eklemek.

Örneğin:

  // 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, bir alt sorgu sonucunda $ key => $ nid biçiminde bir dizidir

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

iyi çalışıyor.

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.