ما هي الطريقة الصحيحة لكتابة استعلام يحتوي على "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)');
في المثال المحدد ، يجب عليك ببساطة كتابة الشرط على النحو التالي:
$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);
}
كما ورد في الشروط الشرطية ("Subselects") ، SelectQuery::condition()
يقبل أيضًا كائنًا ينفذ SelectQueryInterface
كقيمة لـ $value
، مثل ذلك الذي تم إرجاعه بواسطة db_select()
؛ تكمن المشكلة في أنه يمكنك فقط استخدامه عندما تكون قيمة $operator
تساوي "IN"
. راجع لا تعمل الاختيارات الفرعية في شروط DBTNG ، إلا عند استخدامها كقيمة لـ 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();
عند كتابة الاستعلامات المعقدة يجب عليك بالتأكيد استخدام db_query()
بدلاً من db_select()
.
NOT IN
مع استعلام فرعي باستخدام Drupal (إنها تعرف المشكلة قيد العمل).db_select()
.db_query()
.فيما يتعلق باستعلامك ، لست متأكدًا من سبب رغبتك في استخدام استعلام فرعي (ما لم تبسط مثالك)؟ يمكنك كتابتها بسهولة مثل هذا:
SELECT nid
FROM node n INNER JOIN languages l ON n.language = l.language
WHERE language NOT IN ('ab')
DISTINCT
ليس ضروريًا لأن nid
هو مفتاح أساسي لذا لن يتم تكراره.
هناك أيضًا حيث () والتي تسمح بإضافة شرط تعسفي إلى الاستعلام.
مثال:
$query->where('n.language NOT IN (SELECT language FROMlanguages WHERE language = :lang)', array(':lang' => $value));
كما ذكر keithm ، يجب عليك استخدام db_select () و addTag ('node_access') عند تحديد العقد التي يتم عرضها بعد ذلك للمستخدمين.
أسهل طريقة لاستخدام db_select مع تحديد IN 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);
حيث يكون $ subquery_values عبارة عن صفيف من $ key => $ nid format نتيجة لاستعلام فرعي
$query->condition('node.nid', array_values($subquery_values), "NOT IN");
أنه يعمل بشكل جيد.