Advanced SELECTs
- To use SELECT statements to retrieve calculated values.
- To work with aggregate functions and grouping.
- To work with SQL's data manipulation functions.
Calculated Fields
Calculated fields are fields that do not exist in a table, but are created in the SELECT statement. For example, you might want to create FullName from FirstName and LastName.
Concatenation
Concatenation is a fancy word for stringing together different words or characters. SQL Server, Oracle and MySQL each has its own way of handling concatenation. All three of the code samples below will return the following results:
In SQL Server, the plus sign (+) is used as the concatenation operator.
Code Sample: AdvancedSelects/Demos/Concatenate-SqlServer.sql
-- Select the full name of all employees. SQL SERVER. SELECT FirstName + ' ' + LastName FROM Employees;
In Oracle, the double pipe (||) is used as the concatenation operator.
Code Sample: AdvancedSelects/Demos/Concatenate-Oracle.sql
-- Select the full name of all employees. Oracle. SELECT FirstName || ' ' || LastName FROM Employees;
MySQL does this in yet another way. There is no concatenation operator. Instead, MySQL uses the CONCAT() function .
Code Sample: AdvancedSelects/Demos/Concatenate-MySQL.sql
-- Select the full name of all employees. MySQL. SELECT CONCAT(FirstName, ' ', LastName) FROM Employees;
Note that concatenation only works with strings. To concatenate other data types, you must first convert them to strings.
Mathematical Calculations
Mathematical calculations in SQL are similar to those in other languages.
| Operator | Description |
|---|---|
| + | Addition |
| - | Subtraction |
| * | Multiplication |
| / | Division |
| % | Modulus |
Code Sample: AdvancedSelects/Demos/MathCalc.sql
/* If the cost of freight is greater than or equal to $500.00, it will now be taxed by 10%. Create a report that shows the order id, freight cost, freight cost with this tax for all orders of $500 or more. */ SELECT OrderID, Freight, Freight * 1.1 FROM Orders WHERE Freight >= 500;
The above SELECT statement will return the following results:
![]()
Aliases
You will notice in the examples above that the calculated columns have the header "(No column name)". The keyword AS is used to provide a named header for the column.
Code Sample: AdvancedSelects/Demos/Alias.sql
SELECT OrderID, Freight, Freight * 1.1 AS FreightTotal FROM Orders WHERE Freight >= 500;
As you can see, the third column now has the title "FreightTotal".
Aggregate Functions and Grouping
Aggregate Functions
Aggregate functions are used to calculate results using field values from multiple records. There are five common aggregate functions.
| Aggregate Function | Description |
|---|---|
| COUNT() | Returns the number of rows containing non-NULL values in the specified field. |
| SUM() | Returns the sum of the non-NULL values in the specified field. |
| AVG() | Returns the average of the non-NULL values in the specified field. |
| MAX() | Returns the maximum of the non-NULL values in the specified field. |
| MIN() | Returns the minimum of the non-NULL values in the specified field. |
Code Sample: AdvancedSelects/Demos/Aggregate-Count.sql
-- Find the Number of Employees SELECT COUNT(*) AS NumEmployees FROM Employees;
Returns 9.
Code Sample: AdvancedSelects/Demos/Aggregate-Sum.sql
-- Find the Total Number of Units Ordered of Product ID 3 /****************************** SQL Server ******************************/ SELECT SUM(Quantity) AS TotalUnits FROM "Order Details" WHERE ProductID=3; /****************************** Oracle and MySQL ******************************/ SELECT SUM(Quantity) AS TotalUnits FROM Order_Details WHERE ProductID=3;
Returns 328.
Code Sample: AdvancedSelects/Demos/Aggregate-Avg.sql
-- Find the Average Unit Price of Products SELECT AVG(UnitPrice) AS AveragePrice FROM Products;
Returns 28.8663.
Code Sample: AdvancedSelects/Demos/Aggregate-MinMax.sql
-- Find the Earliest and Latest Dates of Hire SELECT MIN(HireDate) AS FirstHireDate, MAX(HireDate) AS LastHireDate FROM Employees;
The above SELECT statement will return April 1, 1992 and November 15, 1994 as the FirstHireDate and LastHireDate, respectively. The date format will vary from database to database.
![]()
Grouping Data
GROUP BY
With the GROUP BY clause, aggregate functions can be applied to groups of records based on column values. For example, the following code will return the number of employees in each city.
Code Sample: AdvancedSelects/Demos/Aggregate-GroupBy.sql
--Retrieve the number of employees in each city SELECT City, COUNT(EmployeeID) AS NumEmployees FROM Employees GROUP BY City;
The above SELECT statement will return the following results:
HAVING
The HAVING clause is used to filter grouped data. For example, the following code specifies that we only want information on cities that have more than one employee.
Code Sample: AdvancedSelects/Demos/Aggregate-Having.sql
/* Retrieve the number of employees in each city in which there are at least 2 employees. */ SELECT City, COUNT(EmployeeID) AS NumEmployees FROM Employees GROUP BY City HAVING COUNT(EmployeeID) > 1;
The above SELECT statement will return the following results:
Order of Clauses
- SELECT
- FROM
- WHERE
- GROUP BY
- HAVING
- ORDER BY
Code Sample: AdvancedSelects/Demos/Aggregate-OrderOfClauses.sql
/* Find the number of sales representatives in each city that contains at least 2 sales representatives. Order by the number of employees. */ SELECT City, COUNT(EmployeeID) AS NumEmployees FROM Employees WHERE Title = 'Sales Representative' GROUP BY City HAVING COUNT(EmployeeID) > 1 ORDER BY NumEmployees;
The above SELECT statement will return the following results:
Grouping Rules
- Every non-aggregate column that appears in the SELECT clause must also appear in the GROUP BY clause.
- You may not use aliases in the HAVING clause.
- You may use aliases in the ORDER BY clause.
- You may only use calculated fields in the HAVING clause.
- You may use calculated field aliases or actual fields in the ORDER BY clause.
Selecting Distinct Records
The DISTINCT keyword is used to select distinct combinations of column values from a table. For example, the following example shows how you would find all the distinct cities in which Northwind has employees.
Code Sample: AdvancedSelects/Demos/Distinct.sql
/* Find all the distinct cities in which Northwind has employees. */ SELECT DISTINCT City FROM Employees ORDER BY City
DISTINCT is often used with aggregate functions. The following example shows how DISTINCT can be used to find out in how many different cities Northwind has employees.
Code Sample: AdvancedSelects/Demos/Distinct-Count.sql
/* Find out in how many different cities Northwind has employees. */ SELECT COUNT(DISTINCT City) AS NumCities FROM Employees
Built-in Data Manipulation Functions
In this section, we will discuss some of the more common built-in data manipulation functions. Unfortunately, the functions differ greatly between databases, so you should be sure to check your database documentation when using these functions.
The tables below show some of the more common math, string, and date functions.
Common Math Functions
| Description | SQL Server | Oracle | MySQL |
|---|---|---|---|
| Absolute value | ABS | ABS | ABS |
| Smallest integer >= value | CEILING | CEIL | CEILING |
| Round down to nearest integer | FLOOR | FLOOR | FLOOR |
| Power | POWER | POWER | POWER |
| Round | ROUND | ROUND | ROUND |
| Square root | SQRT | SQRT | SQRT |
| Formatting numbers to two decimal places | CAST(num AS decimal(8,2)) | TO_CHAR(num,'9.00') | FORMAT(num,2) |
Code Sample: AdvancedSelects/Demos/Functions-Math1.sql
/* Select freight as is and freight rounded to the first decimal (e.g, 1.150 becomes 1.200) from the Orders tables */ SELECT Freight, ROUND(Freight,1) AS ApproxFreight FROM Orders;
The above SELECT statement will return the following results (not all rows shown):
![]()
Code Sample: AdvancedSelects/Demos/Functions-Math2.sql
/* Select the unit price as is and unit price as a decimal with 2 places to the right of the decimal point from the Products tables */ /****************************** SQL Server and MySQL ******************************/ SELECT UnitPrice, CAST(UnitPrice AS Decimal(8,2)) FROM Products; /****************************** Oracle ******************************/ SELECT UnitPrice, TO_CHAR(UnitPrice,'999.99') FROM Products;
The above SELECT statement will return the following results (not all rows shown):
![]()
Note that you would round to a whole number by passing 0 as the second parameter: ROUND(field,0); and to the tens place by passing -1: ROUND(field,-1).
Common String Functions
| Description | SQL Server | Oracle | MySQL |
|---|---|---|---|
| Convert characters to lowercase | LOWER | LOWER | LOWER |
| Convert characters to uppercase | UPPER | UPPER | UPPER |
| Remove trailing blank spaces | RTRIM | RTRIM | RTRIM |
| Remove leading blank spaces | LTRIM | LTRIM | LTRIM |
| Substring | SUBSTRING | SUBSTR | SUBSTRING |
Code Sample: AdvancedSelects/Demos/Functions-String1.sql
/* Select first and last name from employees in all uppercase letters */ SELECT UPPER(FirstName), UPPER(LastName) FROM Employees;
The above SELECT statement will return the following results:
![]()
Code Sample: AdvancedSelects/Demos/Functions-String2.sql
-- Select the first 10 characters of each customer's address /****************************** SQL Server and MySQL ******************************/ SELECT SUBSTRING(Address,1,10) FROM Customers; /****************************** Oracle ******************************/ SELECT SUBSTR(Address,1,10) FROM Customers;
The above SELECT statement will return the following results (not all rows shown):
![]()
Common Date Functions
| Description | SQL Server | Oracle | MySQL |
|---|---|---|---|
| Date addition | DATEADD | (use +) | DATE_ADD |
| Date subtraction | DATEDIFF | (use -) | DATEDIFF |
| Convert date to string | DATENAME | TO_CHAR | DATE_FORMAT |
| Convert date to number | DATEPART | TO_NUMBER(TO_CHAR) | EXTRACT |
| Get current date and time | GETDATE | SYS_DATE | NOW |
Code Sample: AdvancedSelects/Demos/Functions-Date1.sql
-- Find the hiring age of each employee /****************************** SQL Server ******************************/ SELECT LastName, BirthDate, HireDate, DATEDIFF(year,BirthDate,HireDate) AS HireAge FROM Employees ORDER BY HireAge; /****************************** Oracle ******************************/ SELECT LastName, BirthDate, HireDate, FLOOR((HireDate - BirthDate)/365.25) AS HireAge FROM Employees ORDER BY HireAge; /****************************** MySQL ******************************/ -- Find the hiring age of each employee -- in versions of MySQL prior to 4.1.1 SELECT LastName, BirthDate, HireDate, YEAR(HireDate)-YEAR(BirthDate) AS HireAge FROM Employees; -- In MySQL 4.1.1 and later, DATEDIFF() returns the number of days between -- two dates. You can then divide and floor to get age. SELECT LastName, BirthDate, HireDate, FLOOR(DATEDIFF(HireDate,BirthDate)/365) AS HireAge FROM Employees ORDER BY HireAge;
The above SELECT statement will return the following results in SQL Server:
![]()
And like this in Oracle:
![]()
Note for SQL Server users: SQL Server is subtracting the year the employee was born from the year (s)he was hired. This does not give us an accurate age. We'll fix this in an upcoming exercise.
Code Sample: AdvancedSelects/Demos/Functions-Date2.sql
-- Find the Birth month for every employee /****************************** SQL Server ******************************/ SELECT FirstName, LastName, DATENAME(month,BirthDate) AS BirthMonth FROM Employees ORDER BY DATEPART(month,BirthDate); /****************************** Oracle ******************************/ SELECT FirstName, LastName, TO_CHAR(BirthDate,'MONTH') AS BirthMonth FROM Employees ORDER BY TO_NUMBER(TO_CHAR(BirthDate,'MM')); /****************************** MySQL ******************************/ SELECT FirstName, LastName, DATE_FORMAT(BirthDate, '%M') AS BirthMonth FROM Employees ORDER BY EXTRACT(MONTH FROM BirthDate);
The above SELECT statement will return the following results:
![]()
Advanced SELECTs Conclusion
In this lesson of the SQL tutorial, you have continued to use SELECT to create reports from data stored in a single table. In the next lesson, you will learn to create reports from data in multiple tables.
