How to use NOT IN in a condition

Published on April 26, 2007 and tagged with cakephp  model  sql

Yesterday, moeffju asked in a comment to the post “Using an IN list in a condition” how to use NOT IN in SQL queries generated by CakePHP. A good question as the solution is not that obvious (at least if you use the array syntax for conditions).

First the obvious solution:

$this->User->findAll('User.id NOT IN (1, 2, 3)');

And here the solution using the array syntax:

$this->User->findAll(array('NOT' => array('User.id' => array(1, 2, 3))));

18 comments baked

  • Dejan Ranisavljevic April 26, 2007 at 12:25

    Why is this solution better? I don’t see a point …

  • dz April 26, 2007 at 14:00

    the second one is useful if you have data in array form already. you do not have to transform them to text.

  • http://getopenid.com/nik April 26, 2007 at 15:46

    I think it’s also possible to use
    $this->User->findAll(array(‘User.id’=>’NOT IN (1, 2, 3)’);
    so the important part is that first parameter is column name.
    I saw this in the groups and it’s working to me. I am with 1.2 of course.

    Regards

  • Brandon April 26, 2007 at 17:50

    Is there a way to do “OR” conditions with the array format?

  • othman ouahbi April 26, 2007 at 18:39

    Brandon, same syntax as NOT

  • cakebaker April 26, 2007 at 18:47

    @all: Thanks for your comments!

    @Dejan: A second advantage of the array syntax is that the data is automatically escaped.

    @Nik: Your approach doesn’t work here with the latest version of 1.2 from svn. The generated SQL is:

    WHERE `User`.`id` NOT 'IN (1, 2, 3)'
    

    which causes an SQL error.

    @Brandon: Yes, that’s possible. You can find an example at http://cakebaker.42dh.com/2007/01/23/sugar-icing-on-the-cake/

  • moeffju April 27, 2007 at 00:07

    Thanks for the replies. It seems that Cake is quite consistent, which is a good thing. Despite being a Cake newbie, my first impulse on how to use NOT IN was correct. I’m curiously awaiting my first run-ins with AJAXy In-Place editing and building a Moderation system in Cake :)

  • cakebaker April 27, 2007 at 16:30

    @moeffju: Good luck with your application :)

  • Diego April 27, 2007 at 18:26

    If you have a few ids in your array it is fin to use IN, but if you have a considerable amount of data, try turning it to ors or ands, because mysql will optimize it better and your queries will run smoother.

  • cakebaker April 28, 2007 at 11:39

    Diego: Do you have a link for that? I just thought an IN list is syntactical sugar which behind the scenes is resolved to ORs.

  • Diego April 29, 2007 at 01:36

    I didn’t had any information other than experimentation to backup the assertion I made earlier when I posted the comment, but after some research and reading the MySql manual I found something similar maybe not the exact same thing but it may be of interest to some of us.
    How to optimize IN/ANY Subquery
    href=”http://dev.mysql.com/doc/refman/5.0/en/in-subquery-optimization.html

  • cakebaker April 29, 2007 at 09:58

    @Diego: Thanks for the link!

  • moeffju July 25, 2007 at 21:01

    Oh well, development was fine as long as everything was read-only, but actually saving data and implementing a system where users can suggest edits and a moderator can accept or deny them… that sucks. Are there any good tutorials on saving huge models with lots of related models?

  • cakebaker July 26, 2007 at 11:21

    @moeffju: I am not aware of such a tutorial…

  • ohcibi November 04, 2008 at 19:04

    even if
    $this->User->findAll(array(’User.id’=>’NOT IN (1, 2, 3)’);
    would work it makes no sense at all.

    the point is, that we want to keep our 1,2,3 in an array and not transform them into text….

  • cakebaker November 06, 2008 at 17:25

    @ohcibi: Well, the second approach mentioned in the article uses an array ;-)

    Since I wrote this article the find(‘all’) syntax has been introduced and so the modified example looks like:

    $this->User->find('all', array('conditions' => array('NOT' => array('User.id' => array(1, 2, 4)))));
    

    Hope that helps!

  • Luiz Lopes March 26, 2009 at 18:22

    This worked with what I am trying to do. I’m using

    $this->set('agents',$this->Contract->User->find('list',array(
    			'fields' => array('User.id','User.username'),
    			'conditions' => array('User.active =' => '1',
    							'NOT' => array(
    								'User.username' => array('admin',$this->Auth->user('username'))
    							))
    			))
    );

    Which produces the following:
    SELECT `User`.`id`, `User`.`username` FROM `users` AS `User` WHERE `User`.`active` = 1 AND NOT (`User`.`username` IN ('admin', 'user'))

  • cakebaker March 31, 2009 at 16:39

    @Luiz: Thanks for your example!

Bake a comment




(for code please use <code>...</code> [no escaping necessary])

© daniel hofstetter. Licensed under a Creative Commons License