IS6146 Databases for Management Information Systems Lecture 4: SQL IV – SQL Functions and Procedures Rob Gleasure robgleasure.com
IS6146 Today’s session SQL Functions SQL Aggregate Functions SQL Scalar Functions Creating Procedures in Oracle Exercise
SQL Functions Sometimes there are complex tasks or calculations we will need to perform again and again Rather than spell them out each time, we refer to these functions by name SQL provides us with a set of inbuilt functions for common needs Aggregate functions return a value calculated from data in a column, e.g. AVG (), COUNT(), FIRST(), LAST(), MAX(), MIN(), SUM() Scalar functions return an adapted value for each column e.g. UCASE(), LCASE(), MID(), LEN(), ROUND(), and NOW()
AVG() Returns the average value of a numeric column, either directly or stored in a variable Syntax: SELECT AVG(col_name) AS var_name FROM table_name E.g. SELECT AVG(Price) AS PriceAverage FROM Products;
COUNT() Returns the number of rows that matches a specified criteria Syntax: SELECT COUNT(col_name) AS var_name FROM table_name E.g. SELECT COUNT(CustomerID) AS NumberOfCustomer FROM Orders; nt_all Note null values will not be included but duplicates will unless DISTINCT is added, e.g. SELECT COUNT(DISTINCT CustomerID) AS NumberOfCustomer FROM Orders;
FIRST() and LAST() Returns the returns the first and last value of the selected column, respectively Syntax: SELECT FIRST(Col_Name) AS Var_Name FROM Table_Name; E.g. SELECT FIRST(CustomerName) AS FirstCustomer FROM Customers; &ss=-1 Unfortunately this only works for MS Access…
First() and Last() Oracle Workarounds To get the first record in Oracle, we use the following Syntax: SELECT Col_Name FROM Table_Name WHERE ROWNUM <=1; E.g. SELECT CustomerName FROM Customers WHERE ROWNUM <=1; We can get the last by reverse ordering the records E.g. SELECT CustomerName FROM Customers WHERE ROWNUM <=1 ORDER BY CustomerID DESC;
MAX() and MIN() Returns the largest or smallest value of the selected column, respectively Syntax: SELECT MAX(col_name) AS var_name FROM table_name E.g. SELECT MAX(Price) AS HighestPrice FROM Products;
GROUP BY Sometimes we want to retrieve some computed value (average, min, max, etc.) but we want to retrieve these values in groups The syntax for these queries uses GROUP BY, as follows SELECT column_name, aggregate_function(column_name2) FROM table_name WHERE column_name condition GROUP BY column_name; oupby
HAVING The WHERE condition can’t be used with aggregate functions, so we use a different term HAVING E.g. SELECT column_name, aggregate_function(column_name) FROM table_name WHERE column_name operator value GROUP BY column_name HAVING aggregate_function(column_name) condition; ving
UCASE() and LCASE() Returns the value of a field in upper or lowercase, respectively Syntax: SELECT UCASE(column_name) FROM table_name; E.g. SELECT UCASE(SupplierName) AS UC_SNm FROM Suppliers; e&ss=-1
MID() Returns the characters within a text field Syntax: SELECT MID(col_name,start,length) AS var_nm FROM table_name; E.g. SELECT MID(Phone,2,3) AS ThreeDigitAreaCode FROM Suppliers WHERE Phone LIKE '(___)%'; &ss=-1 The first character = 1 Specifying the length is optional
LEN() Returns the returns the length of the value in a text field Syntax: SELECT LEN (column_name) FROM table_name; E.g. SELECT CustomerName,City, LEN(PostalCode) as LengthOfPostCode FROM Customers; ss=-1
ROUND() Returns a numeric field rounded to the number of decimals specified Syntax: SELECT ROUND(column_name,decimals) FROM table_name; E.g. SELECT ProductName, ROUND(Price,0) AS RoundedPrice FROM Products;; d
NOW() Returns the current time and data in the format Month/Day/Year Hour:Minute:Second AM/PM Syntax: SELECT NOW() FROM table_name; E.g. SELECT ShipperName, NOW() AS Shippers11Feb FROM Shippers; &ss=-1
Creating New Procedures As you might imagine, we can also create new functions (called procedures) where we have recurring actions that are not captured in the standard SQL functions This requires the use of programming languages that extend SQL to allow programmatic necessities such as Variables and constants Loops and conditions Triggers and exceptions In MS Access, the language used is T-SQL In Oracle, the language used is PL/SQL
Basic Structure of PL/SQL /* These things on either side of this text indicate comments, meaning all this text is ignored */ DECLARE /* Variables are declared in here */ BEGIN /* SQL queries may be called here, as may other in- built functions such as printing things to the screen or combining or manipulating data */ END; /* That backslash after this in the bottom-left indicates to execute the block */ /
Variables in PL/SQL DECLARE /* Variables are declared by stating a name, a type, and optionally a size, e.g. below */ EmployeeID number(8); BEGIN /* Values may be set for variables either directly */ EmployeeID := ; /* … or from SQL queries*/ SELECT MAX(EmployeeID) AS EmployeeID FROM Employees; END; / Every line ends with a semi-colon
Conditional Statements in PL/SQL DECLARE EmployeeID number(8); BEGIN SELECT MAX(EmployeeID) AS EmployeeID FROM Employees; /* Based on some conditions, we may choose to take alternative actions using IF/ELSE IF statements, e.g. below*/ IF (EmployeeID < ) THEN / * Take some action */ ELSE / * Take some other action */ END IF; END; /
Iterative Statements in PL/SQL DECLARE EmployeeID number(8); Counter number(2); BEGIN Counter := 0; /* We may also want to repeat some action until some condition is met, e.g. below */ WHILE (Counter < 20) LOOP SELECT MAX(EmployeeID) AS EmployeeID FROM Employees; DELETE FROM Employees WHERE EmployeeID = EmployeeID; Counter := Counter + 1; END LOOP; END; /
Triggers in PL/SQL /* We can also triggers things cur on specific actions, e.g. below */ CREATE TRIGGER deleted_employee_trigger BEFORE DELETE ON Employees FOR EACH ROW BEGIN /* This query will fire when an employee is deleted and save their ID and the date they’re deleted into a backup table */ INSERT INTO Deleted_Employees (EmployeeID,DateDeleted) VALUES (:old.EmployeeID, NOW()); END; / This is the way we refer to the previous values in the record causing the trigger
Obviously Just Scratching the Surface Here… There’s a great tutorial at Great tutorial at please have a look through it at your leisure
Exercise Consider the following problems, what queries best solve them? 1. We want to select the average Quantity for each ProductID in the OrderDetails table? 2. We want to create the same result but with the ProductName from the Products table instead of the ProductID (Hint – use LEFT JOIN)?
Exercise 3. We want to create the same result but with the AverageQuantity rounded to two decimal places? 4. We want the same result but displayed according to the first three letters of the ProductName in upper case, e.g. CompanyAbbrevAverageQuantity ALI ANI 40