David Poole en SQLServerCentral hace una revisión de algunos nuevos comandos en SQL Server 2008, por caso:
INTERSECT
EXCEPT
ALL
ANY
ALL y ANY no son nuevos, pero INTERSECT y EXCEPT son nuevos.
INTERSECT, EXCEPT and UNION
Para experimentar con esos comandos David decidió ver dos conjuntos de valores para CustomerID.
Customers (Clientes) en sales territory 10 (United Kingdom)
(pedidos) Sales orders de July 2004, el cual es el último mes de pedidos en Adventureworks
La mejor manera de ver que hacen estos dos comandos es comparar los datos en los diagramas.
redicate | Illustration | Description |
EXCEPT | | Customers (clientes) de UK que no compraron en Julio 2004 |
INTERSECT | | Customers (clientes) de UK
AND (y) que compraron algo en Julio 2004 |
UNION | | Customers (clientes) de UK
OR (o) que hicieron una compra en Julio 2004 |
Diferentes formas de escribir un query con EXCEPT.
Si bien nunca usé EXCEPT antes yo he obtenido los mismos resultados por métodos tradicionales, hay muchas formas de hacer lo mismo, por ejemplo:
LEFT JOIN
Este query trae los resultados requeridos.
SELECT C.CustomerID
FROM Sales.Customer AS C
LEFT JOIN Sales.SalesOrderHeader AS OH
ON C.CustomerID = OH.CustomerID
AND OrderDate>='2004-07-01'
WHERE OH.CustomerID IS NULL
AND C.TerritoryID=10
WHERE CustomerID NOT IN(…)
Buscando la eficiencia, otra forma de hacer lo mismo.
SELECT CustomerID
FROM Sales.Customer
WHERE TerritoryID=10
AND CustomerID NOT IN(
SELECT customerid
FROM Sales.SalesOrderHeader
WHERE OrderDate>='2004-07-01'
)
EXCEPT
Finalmente usando el nuevo comando Except.
SELECT CustomerID
FROM Sales.Customer
WHERE TerritoryID=10
EXCEPT
SELECT customerid
FROM Sales.SalesOrderHeader
WHERE OrderDate>='2004-07-01'
Diferentes maneras de escribir un query tipo INTERSECT
Tres ejemplos:
INNER JOIN
Como un cliente puede tener mas de un pedido tengo que hacer una lista con distinct para los valores del customerid, veamos dos enfoques para lo mismo.
As any customer can have more than one order I am going to have to make a distinct list of CustomerID values. I decided to try a couple of approaches.
SELECT DISTINCT C.CustomerID
FROM Sales.Customer AS C
INNER JOIN Sales.SalesOrderHeader AS OH
ON C.CustomerID = OH.CustomerID
WHERE
C.TerritoryID=10
AND OH.OrderDate>='2004-07-01'
SELECT C.CustomerID
FROM Sales.Customer AS C
INNER JOIN (SELECT DISTINCT CustomerID FROM Sales.SalesOrderHeader WHERE OrderDate>='2004-07-01'
)AS OH
ON C.CustomerID = OH.CustomerID
WHERE C.TerritoryID=10
WHERE CustomerID IN(…)
SELECT CustomerID
FROM Sales.Customer
WHERE TerritoryID=10
AND CustomerID IN(
SELECT customerid
FROM Sales.SalesOrderHeader
WHERE OrderDate>='2004-07-01'
)
INTERSECT
Finalmente un intersect.
SELECT CustomerID
FROM Sales.Customer
WHERE TerritoryID=10
INTERSECT
SELECT customerid
FROM Sales.SalesOrderHeader
WHERE OrderDate>='2004-07-01'
The ANY and ALL Predicate
ANY and ALL are predicates I have never needed to use.
ANY
Los dos queries nos ofrecen los mismos resultados y el mismo plan de ejecución:
SELECT *
FROM Sales.SalesPerson
WHERE TerritoryID = ANY(
SELECT TerritoryID FROM Sales.SalesTerritory WHERE CountryRegionCode='US'
)
SELECT *
FROM Sales.SalesPerson
WHERE TerritoryID IN(
SELECT TerritoryID FROM Sales.SalesTerritory WHERE CountryRegionCode='US'
)
ALL
All permite una comparación contra todos los valores en una lista de un select, por caso estos dos queries son idénticos:
SELECT *
FROM Sales.SalesOrderHeader
WHERE TotalDue > ALL(SELECT TotalDue FROM Sales.TopSales)
ORDER BY Sales.TotalDue DESC
SELECT *
FROM Sales.SalesOrderHeader
WHERE TotalDue > (SELECT MAX(TotalDue) FROM Sales.TopSales)
ORDER BY Sales.TotalDue DESC
La página original se encuentra en:
http://www.sqlservercentral.com/articles/T-SQL/67545/
Twitter: @bernachea