Làm cách nào để sử dụng phiên bản KHÔNG CÓ IN trong một truy vấn?


26

Cách thích hợp để viết một truy vấn có chứa 'KHÔNG VÀO' bằng cách sử dụng câu lệnh điều kiện là gì?

Truy vấn của tôi là một trong những sau đây:

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

Tôi đã thử một cái gì đó như sau:

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

Có thể tôi đang thiếu điều hiển nhiên, nhưng sự khác biệt giữa truy vấn của bạn là SELECT nid FROM node WHERE language != 'ab'gì?
ЕЕннн

Câu trả lời:


38

Trong ví dụ cụ thể, bạn chỉ cần viết điều kiện như sau:

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

Trong trường hợp chung, khi bạn cần chọn các hàng trong cơ sở dữ liệu dựa trên các giá trị được trả về từ truy vấn phụ, bạn nên xem xét những điều sau:

  • "KHÔNG VÀO" được chấp nhận là nhà điều hành từ SelectQuery::condition(). Trong thực tế, truy vấn sau đây sẽ được thực hiện:

    $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);
    }
  • Như đã báo cáo trong các mệnh đề có điều kiện ("subselects"), SelectQuery::condition()cũng chấp nhận một đối tượng triển khai SelectQueryInterfacenhư giá trị cho $value, như đối tượng được trả về bởi db_select(); vấn đề là thực sự bạn chỉ có thể sử dụng nó khi giá trị $operatorbằng "IN". Xem phần phụ không hoạt động trong điều kiện DBTNG, trừ khi được sử dụng làm giá trị cho IN .

Cách duy nhất tôi có thể thấy để sử dụng toán tử "KHÔNG VÀO" với truy vấn phụ conditionlà:

  • Thực hiện truy vấn con để có được một mảng
  • Thực hiện truy vấn chính đặt điều kiện như trong đoạn mã sau

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

    $subquery_result là mảng chứa kết quả của truy vấn phụ.

Mặt khác, bạn có thể sử dụng where()như những người khác đã nói, chấp nhận một chuỗi cho phần truy vấn bạn cần thêm.

Hãy nhớ rằng db_select()chậm hơn mà db_query(); bạn nên sử dụng đầu tiên khi bạn biết các truy vấn có thể bị thay đổi bởi các mô-đun khác. Mặt khác, nếu các mô-đun khác không được sử dụng hook_query_alter()để thay đổi truy vấn của bạn, bạn nên sử dụng db_query().
Trong trường hợp truy cập các nút, nếu bạn chỉ cần lấy các nút mà người dùng có quyền truy cập, thì bạn cần sử dụng db_select()và thêm 'node_access'dưới dạng thẻ của truy vấn, với SelectQuery::addTag(). Ví dụ, blog_page_last()sử dụng mã sau đây.

  $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();

Mã tương tự được sử dụng bởi 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();

Dưới đây là ví dụ về truy vấn con cho bộ lọc tùy chỉnh lượt xem tôi đã viết: link
Roger

1
"Các lựa chọn phụ không hoạt động trong các điều kiện DBTNG, ngoại trừ khi được sử dụng làm giá trị cho IN" được cố định trong Drupal 8.3
Jonathan

3

Khi viết các truy vấn phức tạp, bạn chắc chắn nên sử dụng db_query()thay vì db_select().

  1. Bạn không thể viết một NOT INmệnh đề với truy vấn con với API cơ sở dữ liệu Drupal hiện tại (đó là một vấn đề đã được giải quyết).
  2. Nếu bạn không cần truy vấn của mình động (do đó được viết lại bởi các mô-đun khác), đừng bận tâm đến việc viết một câu hỏi phức tạp như vậy db_select().
  3. Các truy vấn con chưa được hỗ trợ tốt (xem câu trả lời trước của tôi) và nếu bạn được sử dụng để viết SQL thì cách đó dễ sử dụng hơn db_query().

Về truy vấn của bạn, tôi không chắc tại sao bạn muốn sử dụng truy vấn con (trừ khi bạn đơn giản hóa mẫu mực của mình)? Bạn có thể viết nó dễ dàng như thế này:

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

DISTINCTkhông cần thiết vì nidlà khóa chính nên nó sẽ không bị trùng lặp.


2
Về # 2, OP đang chọn các nút. AFAIK db_select () là cách duy nhất để cung cấp bất kỳ thẻ 'node_access' cần thiết nào, trong trường hợp đó db_select () sẽ là lựa chọn duy nhất.
keithm

2

Ngoài ra còn có () cho phép thêm một điều kiện tùy ý vào truy vấn.

Thí dụ:

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

Như keithm đã đề cập, bạn phải sử dụng db_select () và addTag ('node_access') khi chọn các nút được hiển thị cho người dùng.


1

Một cách dễ dàng hơn để sử dụng db_select với phần phụ KHÔNG IN chỉ là sử dụng cái ít được biết đến

$ truy vấn-> ở đâu

để thêm một tùy ý nơi điều kiện.

ví dụ:

  // 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

Trong đó $ subquery_values ​​là một mảng có định dạng $ key => $ nid là kết quả của một truy vấn con

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

nó hoạt động tốt.

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.