TIP: ON y WHERE cuando se usen con un INNER JOIN, no tienen alguna diferencia lógica
Esta vez quiero contarles algo curioso con respecto al uso de las cláusulas ON y WHERE. Todos sabemos para que sirven y donde usarlos, así que no voy entrar en este tipo de detalles. Lo curioso está en que las cláusulas ON y WHERE, cuando ON se use con un INNER JOIN, no tendrán alguna diferencia lógica, siendo lo mismo que usar un WHERE (Hay una excepción que es apreciable solamente al usarlo con GROUP BY ALL. Este detalle será motivo de un próximo post!), sin embargo debo dejar claro que cuando la cláusula ON se usa con alguno de los tres tipos de OUTER JOIN ya no sería igual.
Para aclarar mejor la cuestión, vamos analizar el siguiente script donde hacemos un JOIN entre las tablas Products y Categories (de la base de datos Northwind), y donde usamos la cláusula WHERE para realizar el filtro de acuerdo al campo CategoryID. Muy sencillo!.
1: SELECT TOP 5 P.ProductID, P.ProductName, (P.UnitPrice * P.UnitsInStock) AS [Monto], C.CategoryName
2: FROM Products P, Categories C
3: WHERE P.CategoryID=C.CategoryID AND P.ProductName LIKE 'C%'
No olvidar que, a comparación de otros lenguajes de programación, donde el código es procesado en el orden en el que fue escrito, en SQL el procesamiento es muy diferente. Es así que, el procesamiento lógico de la consulta anterior empieza por la cláusula FROM (aqui es donde se construye el producto cartesiano de las tablas Products y Categories, la coma representa a un "JOIN"), luego se procesa la cláusula WHERE, seguido de la cláusula SELECT, y TOP sería procesado al final. De acuerdo a lo dicho, el optimizador de consultas construye el mejor plan de ejecución para consulta.
Ahora vamos a analizar otro script que hace prácticamente lo mismo que el anterior script, pero esta vez usando la cláusula ON con un INNER JOIN. El procesamiento lógico empieza por la cláusula FROM, seguido de JOIN, luego se procesa la cláusula ON, a continuación sigue el procesamiento de la cláusula WHERE, después SELECT y finalmente TOP.
1: SELECT TOP 5 P.ProductID, P.ProductName, (P.UnitPrice * P.UnitsInStock) AS [Monto], C.CategoryName
2: FROM Products P
3: INNER JOIN Categories C
4: ON P.CategoryID=C.CategoryID
5: WHERE P.ProductName LIKE 'C%'
Y que pasó con INNER?, porque no se procesó?, o es que me olvidé de mencionarlo?. Claro que no me olvidé, lo que pasa es que luego de haberse procesado la cláusula ON, debia procesarse la cláusula INNER, pero el optimizador de consulta no toma en cuenta el INNER, saltándose a WHERE. Entonces, siempre que se use una cláusula ON con un INNER JOIN, el procesamiento de INNER no se tomará en cuenta cuando se construya el respectivo plan de ejecución para toda la consulta.
De acuerdo a esto, en la primera consulta cuando se hace un cross entre las dos tablas, el uso de la coma (,) sería "equivalente" a usar un "JOIN".
1: FROM Products P, Categories C
Recuerden que INNER es como si no existiera.
1: FROM Products P INNER JOIN Categories C
Además la cláusula AND del primer script será equivalente al uso de la cláusula WHERE cuando este se use con un INNER JOIN(no estoy loco, así es tomado en cuenta por el optimizador de consulta). De acuerdo a todo lo dicho, y habiéndose explicado el orden del procesamiento lógico para estas dos consultas, el optimizador de consulta nos tendrá listo un mismo plan de ejecución para las dos consultas, (como pudimos apreciar más arriba).
Ahora para variar, puedes analizar los planes de ejecución de estas dos consultas, y obtendrás los mismos resultados: planes de ejecución exactamente iguales.
1: SELECT *
2: FROM orders o, [Order Details] od, Products p
3: WHERE o.orderid=od.orderID AND od.ProductId = p.productID
4:
5: GO
6:
7: SELECT *
8: FROM Orders o INNER JOIN
9: [Order Details] od
10: ON o.orderid=od.Orderid
11: INNER JOIN Products p
12: ON od.Productid = p.ProductID
Espero les haya sido útil!,
Saludos,
Percy Reyes,