views:

149

answers:

2

Can anybody please spot my error, this should be a legal query in SQL shouldn't it??

Unknown column u.usr_auto_key in the ON clause

This is the database schema:

User: (usr_auto_key, name, etc...)
Setting: (set_auto_key, name etc..)
User_Setting: (usr_auto_key, set_auto_key, value)

And this is the query...

        SELECT 
        `u`.`usr_auto_key` AS `u__usr_auto_key`, 
        `s`.`set_auto_key` AS `s__set_auto_key`, 
        `u2`.`usr_auto_key` AS `u2__usr_auto_key`, 
        `u2`.`set_auto_key` AS `u2__set_auto_key`, 
        `u2`.`value` AS `u2__value` 
        FROM `User` `u`, `Setting` `s` 
        LEFT JOIN `User_Setting` `u2` ON `u`.`usr_auto_key` = `u2`.`usr_auto_key` 
        WHERE (`s`.`sct_auto_key` = 1 AND `u`.`usr_auto_key` = 1 AND admin_property is null)
+1  A: 

Try switching User and Settings in the from clause:

SELECT 
        `u`.`usr_auto_key` AS `u__usr_auto_key`, 
        `s`.`set_auto_key` AS `s__set_auto_key`, 
        `u2`.`usr_auto_key` AS `u2__usr_auto_key`, 
        `u2`.`set_auto_key` AS `u2__set_auto_key`, 
        `u2`.`value` AS `u2__value` 
        FROM `Setting` `s`, `Users` `u`
        LEFT JOIN `User_Setting` `u2` ON `u`.`usr_auto_key` = `u2`.`usr_auto_key` 
        WHERE (`s`.`sct_auto_key` = 1 AND `u`.`usr_auto_key` = 1 AND admin_property is null)
Pablo Santa Cruz
lol, would you mind explaining a little..?
Ropstah
is it working?I think if you do: Users u, Settings s left join WHATEVER, you are trying to perform the join on Settings, not Users.
Pablo Santa Cruz
+4  A: 

Don't mix SQL-89 "comma-style" join syntax with SQL-92 JOIN syntax. There are subtle issues with the precedence of these two types of join operations.

In your case, the consequence is that it's evaluating the join condition LEFT JOIN before the u table alias exists. That's why it doesn't know what u.usr_auto_key is.

You can correct this problem by using JOIN syntax for all joins:

SELECT 
  `u`.`usr_auto_key` AS `u__usr_auto_key`, 
  `s`.`set_auto_key` AS `s__set_auto_key`, 
  `u2`.`usr_auto_key` AS `u2__usr_auto_key`, 
  `u2`.`set_auto_key` AS `u2__set_auto_key`, 
  `u2`.`value` AS `u2__value` 
FROM `User` `u` JOIN `Setting` `s`
LEFT JOIN `User_Setting` `u2` ON `u`.`usr_auto_key` = `u2`.`usr_auto_key` 
WHERE (`s`.`sct_auto_key` = 1 AND `u`.`usr_auto_key` = 1 AND admin_property is null)

I didn't see any join condition between u and s in your query, so I assume you intend this to be a Cartesian product?


For more details on the interaction between the two syntax forms for join, see the section Join Processing Changes in MySQL 5.0.12 on the page http://dev.mysql.com/doc/refman/5.0/en/join.html


Re your comment: As I said, it has to do with operator precedence. If you have a SQL query with FROM A, B JOIN C then it evaluates the B JOIN C before it pays any attention to A -- that includes assigning table aliases. So if your join condition for B JOIN C uses the table alias for A you get an error because that alias doesn't exist yet.

If you reverse it and run B, A JOIN C then as it evaluates the join condition for A JOIN C the alias for A is available and it works (in this case at least).

But this is a fragile solution, because you might also need a query that can't be fixed just by reordering A and B. It's better to just stop using the outdated join syntax with commas. Then any join expression has access to all your table aliases and you'll never have this problem in any query.

Bill Karwin
Yes it needs to be a cartesian product. However I was unable to use cross-join. Can you please explain why the `u` alias IS created in Pablos answer just because it is specified second instead of first (as in my original query)?
Ropstah
Thanks for elaborating 'all the way'. I just really need this approach because my ORM framework Doctrine doesn't correctly execute a CROSS JOIN query...
Ropstah
Tip: a cross join is equivalent to an inner join with no condition, or with a condition that is always `true`.
Bill Karwin
In other words, there is really, *really* no reason to use comma-style join syntax.
Bill Karwin