CFUNITED – The premier ColdFusion conference Beyond Basic SQL for CF Nate Nelson
June 28 th – July 1 st 2006 Agenda Some SQL Standards Getting What You Want From a Database Query Optimization
June 28 th – July 1 st 2006 SQL Standards: Formatting NOT FUN SELECT *, Products.ProductID AS Expr1, Products.ProductName AS Expr2, Products.SupplierID AS Expr3, Products.CategoryID AS Expr4, [Order Details].ProductID AS Expr5, [Order Details].UnitPrice AS Expr6, [Order Details].Quantity AS Expr7, [Order Details].Discount AS Expr8, Orders.CustomerID AS Expr9, Orders.EmployeeID AS Expr10, Orders.OrderDate AS Expr11, Orders.*, [Order Details].OrderID AS Expr12, Products.* FROM Products INNER JOIN [Order Details] ON Products.ProductID = [Order Details].ProductID INNER JOIN Orders ON [Order Details].OrderID = Orders.OrderID
June 28 th – July 1 st 2006 SQL Standards: Formatting Much Better SELECT p.ProductID, p.ProductName, p.SupplierID, p.CategoryID, o.ProductID, o.UnitPrice, o.Quantity, o.Discount, o.CustomerID, o.EmployeeID, o.OrderDate, od.OrderID FROM Products as p INNER JOIN [Order Details] as od ON p.ProductID = od.ProductID INNER JOIN Orders as o ON od.OrderID = o.OrderID
June 28 th – July 1 st 2006 SQL Standards - Naming Conventions Use full descriptive words, not abbreviations, where possible Field names should be singular Table names plural Name Views with a descriptor like vGetProductDetails Stored procedures use usp (for user stored procedure) but never use sp_ in SQL Server) like uspGetOrders Use Case Consistency – SQL keywords in Upper, Mixed case in table and field names, etc.
June 28 th – July 1 st 2006 Getting What You Want (from a database) Joining Tables Wild Cards Aggregate Functions Group By Having
June 28 th – July 1 st 2006 Joining Tables INNER JOINS Join like records together from multiple tables SELECT e.LastName,e.FirstName,e.Title,t.TerritoryDescription FROM Employees as e INNER JOIN EmployeeTerritories as et ON e.EmployeeID = et.EmployeeID INNER JOIN Territories as t ON et.TerritoryID = t.TerritoryID OR SELECT e.LastName,e.FirstName,e.Title,t.TerritoryDescription FROM Employees as e, EmployeeTerritories as et, Territories as t WHERE e.EmployeeID = et.EmployeeID AND et.TerritoryID = t.TerritoryID
June 28 th – July 1 st 2006 JOINING TABLES (cont.) OUTER JOINS Can return all rows even if records not found in related table. Can be used to return what records don’t have related record in other table LEFT,RIGHT,FULL
June 28 th – July 1 st 2006 JOINING TABLES (cont.) LEFT OUTER JOIN SELECT c.CustomerID, c.CompanyName, ccd.CustomerID, ccd.CustomerTypeID FROM Customers as c LEFT OUTER JOIN CustomerCustomerDemo as ccd ON c.CustomerID = ccd.CustomerID RIGHT vs LEFT Says which table is controlling, the one on the left or the one on the right of the Join FULL Will Return all records
June 28 th – July 1 st 2006 Wild Cards More available than just ‘a%’ % = Match a string of 0 or more characters _ = Match any single character [xyz] = Match x, y, or z once [a-z] = Match from a to z [^xyz] = Match any character but z, y, or z [^a-z] = Match any character no between a and z * = Access equivalent to % ? = Access equivalent to _
June 28 th – July 1 st 2006 Aggregate Functions Built in to provide common calculations Must be used on a numeric field only AVG(column) - Average values in column MAX(column) – Max value in column MIN(column) – Min value in column SUM(column) – Sum of all values in column COUNT(column) – Number of values in column
June 28 th – July 1 st 2006 Aggregate Functions (cont.) Can use more than one in query SELECT COUNT(ProductID) AS ProdCount, AVG(UnitPrice) AS AvgUnitPrice, MIN(UnitPrice) AS MinPrice, MAX(UnitPrice) AS MaxPrice, SUM(UnitPrice) AS TotalPrice FROM Products Must use alias if pulling value out in CF
June 28 th – July 1 st 2006 Group Aggregate Data Group Aggregate Data SELECT c.CategoryName, COUNT(ProductID) AS ProdCount, AVG(UnitPrice) AS AvgUnitPrice, MIN(UnitPrice) AS MinPrice, MAX(UnitPrice) AS MaxPrice, SUM(UnitPrice) AS TotalPrice FROM Products AS p INNER JOIN Categories as c ON p.CategoryID = c.CategoryID GROUP BY c.CategoryName Any field in select and not aggregate must be in group by
June 28 th – July 1 st 2006 Having Limit Aggregate Data using HAVING SELECT c.CategoryName, COUNT(ProductID) AS ProdCount FROM Products AS p INNER JOIN Categories as c ON p.CategoryID = c.CategoryID GROUP BY c.CategoryName HAVING COUNT(ProductID) > 10 *Great for debugging
June 28 th – July 1 st 2006 Grouping Data With CFoutput Easily Display output in groups of related data Order by on query drives Groups #getEmployeesByDept.DepartmentName# #getEmployeesByDept.FirstName# #getEmployeesByDept.LastName#
June 28 th – July 1 st 2006 Query Optimization Optimization Query Optimization Techniques Query Optimization with ColdFusion
June 28 th – July 1 st 2006 SQL Optimization Techniques When possible use simple search arguments (SARGs) over joins SELECT * FROM Students AS S, Rides as R WHERE S.town = R.town AND S.town = ‘Denver’ SELECT * FROM Students AS S, Rides as R WHERE R.town = ‘Denver’ AND S.town = ‘Denver’
June 28 th – July 1 st 2006 SQL Optimization Techniques When using predicates, use most restrictive ones first. SELECT * FROM Students WHERE gender = ‘female’ AND town = ‘Denver’ SELECT * FROM Students WHERE town = ‘Denver’ AND gender = ‘female’
June 28 th – July 1 st 2006 SQL Optimization Techniques Use caution with the IN predicate Avoid UNIONS Prefer Joins over Nested Queries Use caution when sorting
June 28 th – July 1 st 2006 SQL Optimization Techniques If possible avoid UNIONS SELECT * FROM Personnel WHERE Work = ‘New York’ UNION SELECT * FROM Personnel WHERE home = ‘Chicago’ = SELECT DISTINCT * FROM Personnel WHERE work = ‘New York’ or home = ‘Chicago’
June 28 th – July 1 st 2006 SQL Optimization Techniques Some methods of sorting can cause the query to slow SELECT project, AVG(cost) FROM Tasks GROUP BY project HAVING project = ‘bricklaying’ = SELECT ‘bricklaying’, AVG(cost) FROM Tasks WHERE project = ‘bricklaying’
June 28 th – July 1 st 2006 SQL Optimization Techniques Slower IF statement IF (percentage>95) THEN SET Grade = ‘HIGHEST’; ELSEIF (percentage >=90) THEN SET Grade = ‘HIGH’; ELSEIF (percentage >=80) THEN SET Grade = ‘GOOD’; ELSE SET Grade = ‘AVERAGE’; END IF;
June 28 th – July 1 st 2006 SQL Optimization Techniques Test for most likely conditions first Faster IF Statement IF (percentage<80) THEN SET Grade = ‘AVERAGE’; ELSEIF (percentage >=80 AND percentage <90) THEN SET Grade = ‘GOOD’; ELSEIF (percentage >=90 AND percentage <95) THEN SET Grade = ‘HIGH’; ELSE SET Grade = ‘HIGHEST’; END IF;
June 28 th – July 1 st 2006 Query Optimization With CF Cached Queries If query is cached it will not hit database every request Specify # of queries cached at once in CFAdmin Cached queries reside in memory When limit is reached, oldest is removed cachedwithin or cachedafter of
June 28 th – July 1 st 2006 Query Optimization With CF Cached Queries In order for query to be pulled from Cache, these points must be met. Both queries must have same name Both queries must have same datasource Both queries must have same SQL statement The cached query must have been executed within time span if cachedWithin is used The cached query must have been executed since date specified when using cachedAfter
June 28 th – July 1 st 2006 Query Optimization With CF Query Of Queries Run a query against the database then query that query as if it were a table in a datasource. SELECT PARKNAME, ADDRESS1, CITY, STATE, ZIPCODE FROM Parks ORDER BY PARKNAME SELECT PARKNAME, ADDRESS1, CITY, STATE, ZIPCODE FROM getParks WHERE STATE = 'MD' ORDER BY PARKNAME
June 28 th – July 1 st 2006 Query Optimization With CF Prepared Statements Use tag to specify a bind parameter When SQL statement is processed the database engine parses the sql to make an execution plan. If SQL is same then it can use the execution plan from cache making it much faster.
June 28 th – July 1 st 2006 QA ??? Nate Nelson
June 28 th – July 1 st 2006 Advanced Queries Nested subquery SELECT DISTINCT o.OrderDate, od.ProductID FROM Orders as o INNER JOIN [Order Details] od on o.OrderID = od.OrderID WHERE o.OrderDate = (SELECT MIN(OrderDate) FROM Orders)
June 28 th – July 1 st 2006 Correlated subquery --OrderIDS and OrderDate of the first order for each customer SELECT CustomerID, MIN(OrderDate) as OrderDate INTO #MinOrderDates FROM Orders GROUP BY CustomerID SELECT o.CustomerID, o.OrderID, o.OrderDate FROM Orders O INNER JOIN #MinOrderDates m on o.CustomerID = m.CustomerID AND o.OrderDate = m.OrderDate ORDER BY o.CustomerID DROP TABLE #MinOrderDates
June 28 th – July 1 st 2006 Correlated subqueryCorrelated subquery SELECT o1.CustomerID, o1.OrderID, o1.OrderDate FROM Orders O1 WHERE o1.OrderDate = (SELECT Min(o2.OrderDate) FROM Orders O2 WHERE o2.CustomerID = o1.CustomerID) ORDER BY CustomerID