Best query questions in March 2011

Rails: Why can't you set an association to nil in a where clause?

9 votes

So, I have photos that belong to collections and users. Photos always belong to a user, but may not be assigned to a collection.

In my controller, this works perfectly:

@collection_photos = Photo.where( :collection => @collection, :user => current_user )

However, this fails...

@other_photos = Photo.where( :collection => nil, :user => current_user )

...but this works:

@other_photos = Photo.where( :collection_id => nil, :user => current_user )

When collection is set to nil I get this error message: No attribute named 'collection' exists for tablephotos``

So, if I pass an object it knows to search for collection_id from the symbol :collection, but if I don't pass an object it doesn't seem to be aware of the association.

Am I understanding this correctly? Could anyone explain a little better why :collection=>nil doesn't work?

when you use pass in the conditions into ActiveRecord, it actually tries to analyze the objects that you passed in, is it a string? an array? a hash? and what's in the string, array or hash?

and in your case, a hash, so it's trying to analyze what's in the hash, in the first statement (which works), you passed in a model instance as the value, so it tries to find if there are any associations that mapped to the key your specified and voila, it found it and everything works as planned

in the second case, you passed in nil as the value, now, ActiveRecord sees that it's a nil object, so it decided that it's not an association. note that it doesn't look at the key, but it only looked at the value, thus it tries to find if there's any column that mapped to the key, but it couldn't find, returning an error

in the last case, you passed in nil as the value, same thing, it tried to find a column which mapped to :collection_id, thus it passed in nil as the value in the SQL statement, and it returned successfully

so it's just an unfortunate considerations taken by ActiveRecord that makes the second case not working =)

hope this clarifies! =D

Can someone explain this SQL query to me?

7 votes

I'm reading this article and I'm trying to understand this SQL statement but I am still somewhat new to SQL.

I'm not sure what comment and c refer to.
I think one of them is the table name but I am not sure of the other. Also, apparently there is a subquery within it which I have not had any experience with:

  SELECT c.id, c.user_id, c.body, c.deep, c.lineage, c.parent_id,
         (SELECT COUNT(*) 
            FROM comment 
           WHERE comment.lineage LIKE (CONCAT(c.lineage,'%')) 
             AND comment.lineage != c.lineage) AS replies
    FROM comment as c
ORDER BY c.lineage

SELECT c.id,
       c.user_id,
       c.body, 
       c.deep, 
       c.lineage, 
       c.parent_id, (
       SELECT COUNT(*)
         FROM comment
        where comment.lineage LIKE (CONCAT(c.lineage,'%'))
          AND comment.lineage!=c.lineage)
       as replies
       FROM comment as c 
       order by c.linea

The first list are all the fields to be selected, with the prefix of c which is the alias later to the comment table.

The query in a query is a subquery, which runs that query which does a like and concatenates .clineage with % (which is the wildcard). This subquery result is saved in replies.

The results are ordered by linea.